Subversion Repositories shark

Rev

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