Subversion Repositories shark

Rev

Rev 3 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/* Project:     OSLib
2
 * Description: The OS Construction Kit
3
 * Date:                1.6.2000
4
 * Idea by:             Luca Abeni & Gerardo Lamastra
5
 *
6
 * OSLib is an SO project aimed at developing a common, easy-to-use
7
 * low-level infrastructure for developing OS kernels and Embedded
8
 * Applications; it partially derives from the HARTIK project but it
9
 * currently is independently developed.
10
 *
11
 * OSLib is distributed under GPL License, and some of its code has
12
 * been derived from the Linux kernel source; also some important
13
 * ideas come from studying the DJGPP go32 extender.
14
 *
15
 * We acknowledge the Linux Community, Free Software Foundation,
16
 * D.J. Delorie and all the other developers who believe in the
17
 * freedom of software and ideas.
18
 *
19
 * For legalese, check out the included GPL license.
20
 */
21
 
22
/* File: Vm86.C
23
 *                             
24
 * VM86 mode switch routines!
25
 * This is basically an alternative way of invoking the
26
 * BIOS service routines; it is very useful to support
27
 * native VBE compliant Video card, without writing an explicit driver
28
 */
29
 
40 pj 30
#include <ll/i386/hw-data.h>
31
#include <ll/i386/hw-instr.h>
32
#include <ll/i386/hw-func.h>
2 pj 33
#include <ll/i386/mem.h>
34
#include <ll/i386/x-bios.h>
40 pj 35
#include <ll/i386/x-dosmem.h>
2 pj 36
#include <ll/i386/cons.h>
37
#include <ll/i386/error.h>
38
 
40 pj 39
FILE(VM-86);
2 pj 40
 
41
/*
42
#define __LL_DEBUG__
43
#define __DUMB_CODE__
44
#define __CHK_IO__
45
*/
46
 
40 pj 47
#define VM86_STACK_SIZE 1024 
2 pj 48
 
40 pj 49
extern DWORD ll_irq_table[256];
50
 
2 pj 51
/* TSS optional section */
40 pj 52
static BYTE  vm86_stack0[VM86_STACK_SIZE];
2 pj 53
 
54
static struct {
55
    TSS t;
56
    DWORD io_map[2048];
57
} vm86_TSS;
58
static LIN_ADDR vm86_stack;
59
static LIN_ADDR vm86_iretAddress;
60
 
61
 
40 pj 62
struct registers *global_regs;
2 pj 63
 
64
#ifdef __DUMB_CODE__
65
static LIN_ADDR vm86_code;
66
static BYTE prova86[] = {
40 pj 67
                        0x1e,                   /* push ds              */
68
                        0xb8,0x00,0xb8,         /* mov ax,0xb800        */
69
                        0x8e,0xd8,              /* mov ds,ax            */
70
                        0xbf,0x9e,0x00,         /* mov di,0x009e (158)  */
71
                        0xb0,0x2a,              /* mov ax,'*'           */
72
                        0x88,0x05,              /* mov ds:[di],al       */
73
                        0x1f,                   /* pop ds               */
74
                        0xcd, 0x40,             /*???*/
75
#ifdef __CHK_IO__               
76
                        0xb0, 0x00,             /* movb   $0x0,%al*/
77
                        0x66,0xba, 0x80, 0x00,  /* movw   $0x80,%dx */
78
                        0x66,0xef,              /* outw %ax, (%dx) */
79
#endif          
80
                        0xcf,                   /* iret                 */
81
                        0xf4,                   /* hlt                  */
82
                        0};    
2 pj 83
#endif
84
 
85
#ifdef __LL_DEBUG__
86
static BYTE vm86_retAddr[] = {
40 pj 87
                        0x1e,                   /* push ds              */
88
                        0xb8,0x00,0xb8,         /* mov ax,0xb800        */
89
                        0x8e,0xd8,              /* mov ds,ax            */
90
                        0xbf,0x3e,0x01,         /* mov di,0x013c (316)  */
91
                        0xb0,'%',               /* mov ax,'%'           */
92
                        0x88,0x05,              /* mov ds:[di],al       */
93
                        0x1f,                   /* pop ds               */
94
                        0xcd, 0x48};            /* int 0x48             */
2 pj 95
#else
40 pj 96
static BYTE vm86_retAddr[] = {0xcd, 0x48};      /* int 48h              */
2 pj 97
#endif
98
 
40 pj 99
TSS *vm86_get_tss(void)
100
{
101
    return &(vm86_TSS.t);
102
}
103
 
2 pj 104
/* This is the return point from V86 mode, called through int 0x48
105
 * (see vm86-exc.s). We double check that this function is called in
106
 * the V86 TSS. Otherwise, Panic!!!
107
 */
40 pj 108
void vm86_return(DWORD n, struct registers r)
2 pj 109
{
110
    CONTEXT c = get_TR();
111
#ifdef __LL_DEBUG__
40 pj 112
    DWORD cs,eip;
2 pj 113
    void *esp;
114
    DWORD a;
115
/*    message("Gotta code=%d [0 called from GPF/1 int 0x48]\n",code);*/
116
#endif
117
    if (c == X_VM86_TSS) {
40 pj 118
        global_regs = &r;
2 pj 119
#ifdef __LL_DEBUG__
40 pj 120
        message("TSS CS=%x IP=%lx\n",vm86_TSS.t.cs,vm86_TSS.t.eip);
121
        message("Switching to %x\n", vm86_TSS.t.back_link);
122
        a = (DWORD)(vm86_iretAddress);
123
        cs = (a & 0xFF000) >> 4;
124
        eip = (a & 0xFFF);
125
        message("Real-Mode Address is CS=%lx IP=%lx\nLinear=%lx\n",cs,eip,a);
126
        esp = /* (void *)(tos)*/ 0x69;
127
        message("Stack frame: %p %lx %lx\n",
128
                        esp, vm86_TSS.t.esp0, vm86_TSS.t.esp);
129
        message("%lx ",lmempeekd(esp));         /* bp */
130
        message("%lx ",lmempeekd(esp+4));       /* eip */
131
        message("%lx ",lmempeekd(esp+8));       /* 0x0d */
132
        message("%lx\n",lmempeekd(esp+12));     /* error code */
2 pj 133
/* The error code is given by the selector causing shifted and or-ed with
134
   3 bits: [LDT/GDT | IDT | Ext/Int]
135
   If IDT == 1 -> the fault was provoked bu an interrupt (Internal if the
136
   Ext/Int bit is 0, External if the bit is 1)
137
   Else the LDT/GDT bit shows if the selector belongs to the LDT (if 1)
138
   or GDT (if 0)  
139
*/
40 pj 140
        message("%lx ",lmempeekd(esp+16));      /* EIP of faulting instr */
141
        message("%lx ",lmempeekd(esp+20));      /* CS of faulting instr*/
142
        message("%lx ",lmempeekd(esp+24));      /* EFLAGS*/
143
        message("%lx\n",lmempeekd(esp+28));     /* old ESP*/
144
        message("%lx ",lmempeekd(esp+32));      /* old SS*/
145
        message("%lx ",lmempeekd(esp+36));      /* old ES*/
146
        message("%lx ",lmempeekd(esp+40));      /* old DS*/
147
        message("%lx\n",lmempeekd(esp+44));     /* old FS*/
2 pj 148
#endif
40 pj 149
        ll_context_load(vm86_TSS.t.back_link);
2 pj 150
    }
40 pj 151
        message("Here?\n");
2 pj 152
    halt();
153
}
154
 
155
extern void vm86_exc(void);
156
 
157
/* Just a debugging function; it dumps the status of the TSS */
158
void vm86_dump_TSS(void)
159
{
40 pj 160
    BYTE acc,gran;
161
    DWORD base,lim;
2 pj 162
    message("vm86_TSS.t dump\n");
40 pj 163
    message("Flag: %lx\n",vm86_TSS.t.eflags);
164
    message("SS: %hx SP:%lx\n", vm86_TSS.t.ss,vm86_TSS.t.esp);
165
    message("Stack0: %hx:%lx\n",vm86_TSS.t.ss0,vm86_TSS.t.esp0);
166
    message("Stack1: %hx:%lx\n",vm86_TSS.t.ss1,vm86_TSS.t.esp1);
167
    message("Stack2: %hx:%lx\n",vm86_TSS.t.ss2,vm86_TSS.t.esp2);
168
    message("CS: %hx IP: %lx",vm86_TSS.t.cs, vm86_TSS.t.eip);
169
    message("DS: %hx\n",vm86_TSS.t.ds);
170
    base = GDT_read(X_VM86_TSS,&lim,&acc,&gran);
2 pj 171
    message("Base : %lx Lim : %lx Acc : %x Gran %x\n",
40 pj 172
                    base,lim,(unsigned)(acc),(unsigned)(gran));
2 pj 173
}
174
 
175
void vm86_init(void)
176
{
177
    int register i;
40 pj 178
 
2 pj 179
    /* Init the DOS memory allocator */
40 pj 180
    DOS_mem_init();
2 pj 181
 
182
    /* First of all, we need to setup a GDT entries to
183
     * allow vm86 task execution. We just need a free 386 TSS, which
184
     * will be used to store the execution context of the virtual 8086
185
     * task
186
     */
40 pj 187
    GDT_place(X_VM86_TSS,(DWORD)(&vm86_TSS),
188
              sizeof(vm86_TSS),FREE_TSS386,GRAN_16);
2 pj 189
 
40 pj 190
/* HACKME!!! */
191
//    IDT_place(0x48,vm86_exc);
192
    l1_int_bind(0x48, vm86_return);
193
//    ll_irq_table[0x48] = (DWORD)vm86_return;
194
 
2 pj 195
    /* Prepare a real-mode stack, obtaining it from the
196
     * DOS memory allocator!
197
     * 8K should be OK! Stack top is vm86_stack + SIZE!
198
     */
40 pj 199
    vm86_stack = DOS_alloc(VM86_STACK_SIZE*2);
200
    vm86_stack += VM86_STACK_SIZE/2;
201
 
2 pj 202
    /* Create a location of DOS memory containing the
203
     * opcode sequence which will generate a GPF
204
     * We use the privileged instruction hlt to do it
205
     */
206
    vm86_iretAddress = DOS_alloc(sizeof(vm86_retAddr));
40 pj 207
    memcpy(vm86_iretAddress,vm86_retAddr,sizeof(vm86_retAddr));
2 pj 208
#ifdef __LL_DEBUG__
40 pj 209
    message("PM reentry linear address=0x%lx\n", (DWORD)vm86_iretAddress);
2 pj 210
#endif
211
#ifdef __DUMB_CODE__
212
    vm86_code = DOS_alloc(2048);
40 pj 213
    lmemcpy(vm86_code,prova86,sizeof(prova86));
2 pj 214
#endif
215
    /* Zero the PM/Ring[1,2] ss:esp; they're unused! */
216
    vm86_TSS.t.esp1 = 0;
217
    vm86_TSS.t.esp2 = 0;
218
    vm86_TSS.t.ss1 = 0;
219
    vm86_TSS.t.ss2 = 0;
220
    /* Use only the GDT */
221
    vm86_TSS.t.ldt = 0;
222
    /* No paging activated */
223
    vm86_TSS.t.cr3 = 0;
224
    vm86_TSS.t.trap = 0;
225
    /* Yeah, free access to any I/O port; we trust BIOS anyway! */
226
    /* Here is the explanation: we have 65536 I/O ports... each bit
227
     * in the io_map masks/unmasks the exception for the given I/O port
228
     * If the bit is set, an exception is generated; otherwise, if the bit
229
     * is clear, everythings works fine...
230
     * Because of alignment problem, we need to add an extra byte all set
231
     * to 1, according to Intel manuals
232
     */
40 pj 233
    vm86_TSS.t.io_base = (DWORD)(&(vm86_TSS.io_map)) -
234
                        (DWORD)(&(vm86_TSS));
235
    for (i = 0; i < 2047; i++) vm86_TSS.io_map[i] = 0;
2 pj 236
    vm86_TSS.io_map[2047] = 0xFF000000;
237
}
238
 
40 pj 239
int vm86_callBIOS(int service,X_REGS16 *in,X_REGS16 *out,X_SREGS16 *s)
2 pj 240
{
241
    DWORD vm86_tmpAddr;
40 pj 242
    DWORD vm86_flags, vm86_cs,vm86_ip;
2 pj 243
    LIN_ADDR vm86_stackPtr;
244
    DWORD *IRQTable_entry;
40 pj 245
 
246
    if (service < 0x10 || in == NULL) return -1;
2 pj 247
    /* Setup the stack frame */
40 pj 248
    vm86_tmpAddr = (DWORD)(vm86_stack);
2 pj 249
    vm86_TSS.t.ss = (vm86_tmpAddr & 0xFF000) >> 4;
250
    vm86_TSS.t.ebp = vm86_TSS.t.esp = (vm86_tmpAddr & 0x0FFF)
40 pj 251
                + VM86_STACK_SIZE - 6;
2 pj 252
    /* Build an iret stack frame which returns to vm86_iretAddress */
40 pj 253
    vm86_tmpAddr = (DWORD)(vm86_iretAddress);
2 pj 254
    vm86_cs = (vm86_tmpAddr & 0xFF000) >> 4;
255
    vm86_ip = (vm86_tmpAddr & 0xFFF);
40 pj 256
    vm86_flags = 0; /* CPU_FLAG_VM | CPU_FLAG_IOPL; */
2 pj 257
    vm86_stackPtr = vm86_stack + VM86_STACK_SIZE;
40 pj 258
    lmempokew(vm86_stackPtr-6,vm86_ip);
259
    lmempokew(vm86_stackPtr-4,vm86_cs);
260
    lmempokew(vm86_stackPtr-2,vm86_flags);
2 pj 261
#ifdef __LL_DEBUG__
262
    message("Stack: %lx SS: %lx SP: %lx\n",
40 pj 263
        vm86_tmpAddr + VM86_STACK_SIZE,(DWORD)vm86_TSS.t.ss,vm86_TSS.t.esp);
2 pj 264
#endif
265
    /* Wanted VM86 mode + IOPL = 3! */
266
    vm86_TSS.t.eflags = CPU_FLAG_VM | CPU_FLAG_IOPL;
267
    /* Preload some standard values into the registers */
268
    vm86_TSS.t.ss0 = X_FLATDATA_SEL;
40 pj 269
    vm86_TSS.t.esp0 = (DWORD)&(vm86_stack0[VM86_STACK_SIZE-1]);
270
 
271
 
2 pj 272
#ifdef __DUMB_CODE__
40 pj 273
    vm86_TSS.t.cs = ((DWORD)(vm86_code) & 0xFFFF0) >> 4;
274
    vm86_TSS.t.eip = ((DWORD)(vm86_code) & 0x000F);
2 pj 275
#ifdef __LL_DEBUG_
276
    message("(DUMB CODE) CS:%x IP:%x/%x\n",
40 pj 277
        (DWORD)vm86_TSS.t.cs,vm86_TSS.t.eip,&prova86);
2 pj 278
    message("(DUMB CODE) Go...\n");
279
#endif
280
    vm86_TSS.t.back_link = ll_context_save();
281
    ll_context_load(X_VM86_TSS);
282
 
283
#ifdef __LL_DEBUG_
284
    message("(DUMB CODE) I am back...\n");
285
#endif
286
#else
287
    /* Copy the parms from the X_*REGS structures in the vm86 TSS */
40 pj 288
    vm86_TSS.t.eax = (DWORD)in->x.ax;
289
    vm86_TSS.t.ebx = (DWORD)in->x.bx;
290
    vm86_TSS.t.ecx = (DWORD)in->x.cx;
291
    vm86_TSS.t.edx = (DWORD)in->x.dx;
292
    vm86_TSS.t.esi = (DWORD)in->x.si;
293
    vm86_TSS.t.edi = (DWORD)in->x.di;
2 pj 294
    /* IF Segment registers are required, copy them... */
295
    if (s != NULL) {
40 pj 296
        vm86_TSS.t.es = (WORD)s->es;
297
        vm86_TSS.t.ds = (WORD)s->ds;
2 pj 298
    } else {
40 pj 299
        vm86_TSS.t.ds = vm86_TSS.t.ss;
300
        vm86_TSS.t.es = vm86_TSS.t.ss;
2 pj 301
    }
40 pj 302
    vm86_TSS.t.gs = vm86_TSS.t.ss;
303
    vm86_TSS.t.fs = vm86_TSS.t.ss;
2 pj 304
    /* Execute the BIOS call, fetching the CS:IP of the real interrupt
305
     * handler from 0:0 (DOS irq table!)
306
     */
40 pj 307
    IRQTable_entry = (void *)(0L);
308
    vm86_TSS.t.cs= ((IRQTable_entry[service]) & 0xFFFF0000) >> 16;
2 pj 309
    vm86_TSS.t.eip = ((IRQTable_entry[service]) & 0x0000FFFF);
40 pj 310
#ifdef __LL_DEBUG__    
311
    message("CS:%x IP:%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip);
2 pj 312
#endif
313
    /* Let's use the ll standard call... */
314
    vm86_TSS.t.back_link = ll_context_save();
315
    ll_context_load(X_VM86_TSS);
40 pj 316
#ifdef __LL_DEBUG__    
2 pj 317
    message("I am back...\n");
318
    message("TSS CS=%hx IP=%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip);
40 pj 319
    { char *xp = (char *)(vm86_iretAddress + 0xe);
320
      message("PM reentry linear address=%p\n", vm86_iretAddress);
321
      message("Executing code: %x ",(unsigned char)(*xp)); xp++;
322
      message("%x\n",(unsigned char)(*xp));}
2 pj 323
#endif
324
    /* Send back in the X_*REGS structure the value obtained with
325
     * the real-mode interrupt call
326
     */
327
    if (out != NULL) {
328
/*
329
      out->x.ax = (WORD)vm86_TSS.t.eax;
330
      out->x.bx = (WORD)vm86_TSS.t.ebx;
331
      out->x.cx = (WORD)vm86_TSS.t.ecx;
332
      out->x.dx = (WORD)vm86_TSS.t.edx;
333
      out->x.si = (WORD)vm86_TSS.t.esi;
334
      out->x.di = (WORD)vm86_TSS.t.edi;
335
      out->x.cflag = (WORD)vm86_TSS.t.eflags;
336
*/
337
#ifdef __LL_DEBUG__
40 pj 338
#error Fix the following: use global_regs->xxx ???
339
        message("%x\n", (WORD)*(GLOBesp));
340
        message("%x\n", (WORD)*(GLOBesp+1)); /*EDI*/
341
        message("%x\n", (WORD)*(GLOBesp+2)); /*ESI*/
342
        message("%x\n", (WORD)*(GLOBesp+3)); /*EBP*/
343
        message("%x\n", (WORD)*(GLOBesp+4)); /*ESP*/
344
        message("%x\n", (WORD)*(GLOBesp+5)); /*EBX*/
345
        message("%x\n", (WORD)*(GLOBesp+6)); /*EDX*/
2 pj 346
#endif
40 pj 347
      out->x.ax = global_regs->eax;
348
      out->x.bx = global_regs->ebx;
349
      out->x.cx = global_regs->ecx;
350
      out->x.dx = global_regs->edx;
351
      out->x.si = global_regs->esi;
352
      out->x.di = global_regs->edi;
353
      out->x.cflag = global_regs->flags;
2 pj 354
    }
355
    if (s != NULL) {
40 pj 356
      s->es = vm86_TSS.t.es;
357
      s->ds = vm86_TSS.t.ds;
2 pj 358
    }
359
#endif
360
    return 1;
361
}