Subversion Repositories shark

Rev

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