27,14 → 27,16 |
* native VBE compliant Video card, without writing an explicit driver |
*/ |
|
#include <ll/i386/hw-data.h> |
#include <ll/i386/hw-instr.h> |
#include <ll/i386/hw-func.h> |
#include <ll/i386/mem.h> |
#include <ll/i386/x-bios.h> |
#include <ll/i386/hw-func.h> |
#include <ll/i386/hw-instr.h> |
#include <ll/i386/x-dosmem.h> |
#include <ll/i386/cons.h> |
#include <ll/i386/error.h> |
|
FILE(VM - 86); |
FILE(VM-86); |
|
/* |
#define __LL_DEBUG__ |
42,10 → 44,12 |
#define __CHK_IO__ |
*/ |
|
#define VM86_STACK_SIZE 1024 |
#define VM86_STACK_SIZE 1024 |
|
extern DWORD ll_irq_table[256]; |
|
/* TSS optional section */ |
static BYTE vm86_stack0[VM86_STACK_SIZE]; |
static BYTE vm86_stack0[VM86_STACK_SIZE]; |
|
static struct { |
TSS t; |
55,76 → 59,77 |
static LIN_ADDR vm86_iretAddress; |
|
|
DWORD *GLOBesp; |
struct registers *global_regs; |
|
|
#ifdef __DUMB_CODE__ |
static LIN_ADDR vm86_code; |
static BYTE prova86[] = { |
0x1e, /* push ds */ |
0xb8, 0x00, 0xb8, /* mov ax,0xb800 */ |
0x8e, 0xd8, /* mov ds,ax */ |
0xbf, 0x9e, 0x00, /* mov di,0x009e (158) */ |
0xb0, 0x2a, /* mov ax,'*' */ |
0x88, 0x05, /* mov ds:[di],al */ |
0x1f, /* pop ds */ |
0xcd, 0x40, /*??? */ |
#ifdef __CHK_IO__ |
0xb0, 0x00, /* movb $0x0,%al */ |
0x66, 0xba, 0x80, 0x00, /* movw $0x80,%dx */ |
0x66, 0xef, /* outw %ax, (%dx) */ |
0x1e, /* push ds */ |
0xb8,0x00,0xb8, /* mov ax,0xb800 */ |
0x8e,0xd8, /* mov ds,ax */ |
0xbf,0x9e,0x00, /* mov di,0x009e (158) */ |
0xb0,0x2a, /* mov ax,'*' */ |
0x88,0x05, /* mov ds:[di],al */ |
0x1f, /* pop ds */ |
0xcd, 0x40, /*???*/ |
#ifdef __CHK_IO__ |
0xb0, 0x00, /* movb $0x0,%al*/ |
0x66,0xba, 0x80, 0x00, /* movw $0x80,%dx */ |
0x66,0xef, /* outw %ax, (%dx) */ |
#endif |
0xcf, /* iret */ |
0xf4, /* hlt */ |
0}; |
#endif |
0xcf, /* iret */ |
0xf4, /* hlt */ |
0 |
}; |
#endif |
|
#ifdef __LL_DEBUG__ |
static BYTE vm86_retAddr[] = { |
0x1e, /* push ds */ |
0xb8, 0x00, 0xb8, /* mov ax,0xb800 */ |
0x8e, 0xd8, /* mov ds,ax */ |
0xbf, 0x3e, 0x01, /* mov di,0x013c (316) */ |
0xb0, '%', /* mov ax,'%' */ |
0x88, 0x05, /* mov ds:[di],al */ |
0x1f, /* pop ds */ |
0xcd, 0x48 |
}; /* int 0x48 */ |
0x1e, /* push ds */ |
0xb8,0x00,0xb8, /* mov ax,0xb800 */ |
0x8e,0xd8, /* mov ds,ax */ |
0xbf,0x3e,0x01, /* mov di,0x013c (316) */ |
0xb0,'%', /* mov ax,'%' */ |
0x88,0x05, /* mov ds:[di],al */ |
0x1f, /* pop ds */ |
0xcd, 0x48}; /* int 0x48 */ |
#else |
static BYTE vm86_retAddr[] = { 0xcd, 0x48 }; /* int 48h */ |
static BYTE vm86_retAddr[] = {0xcd, 0x48}; /* int 48h */ |
#endif |
|
TSS *vm86_get_tss(void) |
{ |
return &(vm86_TSS.t); |
} |
|
/* This is the return point from V86 mode, called through int 0x48 |
* (see vm86-exc.s). We double check that this function is called in |
* the V86 TSS. Otherwise, Panic!!! |
*/ |
void vm86_return(DWORD * tos) |
void vm86_return(DWORD n, struct registers r) |
{ |
CONTEXT c = get_TR(); |
#ifdef __LL_DEBUG__ |
DWORD cs, eip; |
DWORD cs,eip; |
void *esp; |
DWORD a; |
/* message("Gotta code=%d [0 called from GPF/1 int 0x48]\n",code);*/ |
#endif |
if (c == X_VM86_TSS) { |
GLOBesp = tos; |
global_regs = &r; |
#ifdef __LL_DEBUG__ |
message("TSS CS=%x IP=%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip); |
message("Switching to %x\n", vm86_TSS.t.back_link); |
a = (DWORD) (vm86_iretAddress); |
cs = (a & 0xFF000) >> 4; |
eip = (a & 0xFFF); |
message("Real-Mode Address is CS=%lx IP=%lx\nLinear=%lx\n", cs, |
eip, a); |
esp = (void *) (tos); |
message("Stack frame: %p %lx %lx\n", |
esp, vm86_TSS.t.esp0, vm86_TSS.t.esp); |
message("%lx ", lmempeekd(esp)); /* bp */ |
message("%lx ", lmempeekd(esp + 4)); /* eip */ |
message("%lx ", lmempeekd(esp + 8)); /* 0x0d */ |
message("%lx\n", lmempeekd(esp + 12)); /* error code */ |
message("TSS CS=%x IP=%lx\n",vm86_TSS.t.cs,vm86_TSS.t.eip); |
message("Switching to %x\n", vm86_TSS.t.back_link); |
a = (DWORD)(vm86_iretAddress); |
cs = (a & 0xFF000) >> 4; |
eip = (a & 0xFFF); |
message("Real-Mode Address is CS=%lx IP=%lx\nLinear=%lx\n",cs,eip,a); |
esp = /* (void *)(tos)*/ 0x69; |
message("Stack frame: %p %lx %lx\n", |
esp, vm86_TSS.t.esp0, vm86_TSS.t.esp); |
message("%lx ",lmempeekd(esp)); /* bp */ |
message("%lx ",lmempeekd(esp+4)); /* eip */ |
message("%lx ",lmempeekd(esp+8)); /* 0x0d */ |
message("%lx\n",lmempeekd(esp+12)); /* error code */ |
/* The error code is given by the selector causing shifted and or-ed with |
3 bits: [LDT/GDT | IDT | Ext/Int] |
If IDT == 1 -> the fault was provoked bu an interrupt (Internal if the |
132,17 → 137,18 |
Else the LDT/GDT bit shows if the selector belongs to the LDT (if 1) |
or GDT (if 0) |
*/ |
message("%lx ", lmempeekd(esp + 16)); /* EIP of faulting instr */ |
message("%lx ", lmempeekd(esp + 20)); /* CS of faulting instr */ |
message("%lx ", lmempeekd(esp + 24)); /* EFLAGS */ |
message("%lx\n", lmempeekd(esp + 28)); /* old ESP */ |
message("%lx ", lmempeekd(esp + 32)); /* old SS */ |
message("%lx ", lmempeekd(esp + 36)); /* old ES */ |
message("%lx ", lmempeekd(esp + 40)); /* old DS */ |
message("%lx\n", lmempeekd(esp + 44)); /* old FS */ |
message("%lx ",lmempeekd(esp+16)); /* EIP of faulting instr */ |
message("%lx ",lmempeekd(esp+20)); /* CS of faulting instr*/ |
message("%lx ",lmempeekd(esp+24)); /* EFLAGS*/ |
message("%lx\n",lmempeekd(esp+28)); /* old ESP*/ |
message("%lx ",lmempeekd(esp+32)); /* old SS*/ |
message("%lx ",lmempeekd(esp+36)); /* old ES*/ |
message("%lx ",lmempeekd(esp+40)); /* old DS*/ |
message("%lx\n",lmempeekd(esp+44)); /* old FS*/ |
#endif |
ll_context_load(vm86_TSS.t.back_link); |
ll_context_load(vm86_TSS.t.back_link); |
} |
message("Here?\n"); |
halt(); |
} |
|
151,27 → 157,27 |
/* Just a debugging function; it dumps the status of the TSS */ |
void vm86_dump_TSS(void) |
{ |
BYTE acc, gran; |
DWORD base, lim; |
BYTE acc,gran; |
DWORD base,lim; |
message("vm86_TSS.t dump\n"); |
message("Flag: %lx\n", vm86_TSS.t.eflags); |
message("SS: %hx SP:%lx\n", vm86_TSS.t.ss, vm86_TSS.t.esp); |
message("Stack0: %hx:%lx\n", vm86_TSS.t.ss0, vm86_TSS.t.esp0); |
message("Stack1: %hx:%lx\n", vm86_TSS.t.ss1, vm86_TSS.t.esp1); |
message("Stack2: %hx:%lx\n", vm86_TSS.t.ss2, vm86_TSS.t.esp2); |
message("CS: %hx IP: %lx", vm86_TSS.t.cs, vm86_TSS.t.eip); |
message("DS: %hx\n", vm86_TSS.t.ds); |
base = GDT_read(X_VM86_TSS, &lim, &acc, &gran); |
message("Flag: %lx\n",vm86_TSS.t.eflags); |
message("SS: %hx SP:%lx\n", vm86_TSS.t.ss,vm86_TSS.t.esp); |
message("Stack0: %hx:%lx\n",vm86_TSS.t.ss0,vm86_TSS.t.esp0); |
message("Stack1: %hx:%lx\n",vm86_TSS.t.ss1,vm86_TSS.t.esp1); |
message("Stack2: %hx:%lx\n",vm86_TSS.t.ss2,vm86_TSS.t.esp2); |
message("CS: %hx IP: %lx",vm86_TSS.t.cs, vm86_TSS.t.eip); |
message("DS: %hx\n",vm86_TSS.t.ds); |
base = GDT_read(X_VM86_TSS,&lim,&acc,&gran); |
message("Base : %lx Lim : %lx Acc : %x Gran %x\n", |
base, lim, (unsigned) (acc), (unsigned) (gran)); |
base,lim,(unsigned)(acc),(unsigned)(gran)); |
} |
|
void vm86_init(void) |
{ |
int register i; |
|
|
/* Init the DOS memory allocator */ |
// DOS_mem_init(); |
DOS_mem_init(); |
|
/* First of all, we need to setup a GDT entries to |
* allow vm86 task execution. We just need a free 386 TSS, which |
178,29 → 184,33 |
* will be used to store the execution context of the virtual 8086 |
* task |
*/ |
GDT_place(X_VM86_TSS, (DWORD) (&vm86_TSS), |
sizeof(vm86_TSS), FREE_TSS386, GRAN_16); |
IDT_place(0x48, vm86_exc); |
GDT_place(X_VM86_TSS,(DWORD)(&vm86_TSS), |
sizeof(vm86_TSS),FREE_TSS386,GRAN_16); |
|
/* HACKME!!! */ |
// IDT_place(0x48,vm86_exc); |
l1_int_bind(0x48, vm86_return); |
// ll_irq_table[0x48] = (DWORD)vm86_return; |
|
/* Prepare a real-mode stack, obtaining it from the |
* DOS memory allocator! |
* 8K should be OK! Stack top is vm86_stack + SIZE! |
*/ |
vm86_stack = DOS_alloc(VM86_STACK_SIZE * 2); |
vm86_stack += VM86_STACK_SIZE / 2; |
|
vm86_stack = DOS_alloc(VM86_STACK_SIZE*2); |
vm86_stack += VM86_STACK_SIZE/2; |
|
/* Create a location of DOS memory containing the |
* opcode sequence which will generate a GPF |
* We use the privileged instruction hlt to do it |
*/ |
vm86_iretAddress = DOS_alloc(sizeof(vm86_retAddr)); |
memcpy(vm86_iretAddress, vm86_retAddr, sizeof(vm86_retAddr)); |
memcpy(vm86_iretAddress,vm86_retAddr,sizeof(vm86_retAddr)); |
#ifdef __LL_DEBUG__ |
message("PM reentry linear address=%p\n", vm86_iretAddress); |
message("PM reentry linear address=0x%lx\n", (DWORD)vm86_iretAddress); |
#endif |
#ifdef __DUMB_CODE__ |
vm86_code = DOS_alloc(2048); |
lmemcpy(vm86_code, prova86, sizeof(prova86)); |
lmemcpy(vm86_code,prova86,sizeof(prova86)); |
#endif |
/* Zero the PM/Ring[1,2] ss:esp; they're unused! */ |
vm86_TSS.t.esp1 = 0; |
220,55 → 230,51 |
* Because of alignment problem, we need to add an extra byte all set |
* to 1, according to Intel manuals |
*/ |
vm86_TSS.t.io_base = (DWORD) (&(vm86_TSS.io_map)) - |
(DWORD) (&(vm86_TSS)); |
for (i = 0; i < 2047; i++) |
vm86_TSS.io_map[i] = 0; |
vm86_TSS.t.io_base = (DWORD)(&(vm86_TSS.io_map)) - |
(DWORD)(&(vm86_TSS)); |
for (i = 0; i < 2047; i++) vm86_TSS.io_map[i] = 0; |
vm86_TSS.io_map[2047] = 0xFF000000; |
} |
|
int vm86_callBIOS(int service, X_REGS16 * in, X_REGS16 * out, |
X_SREGS16 * s) |
int vm86_callBIOS(int service,X_REGS16 *in,X_REGS16 *out,X_SREGS16 *s) |
{ |
DWORD vm86_tmpAddr; |
DWORD vm86_flags, vm86_cs, vm86_ip; |
DWORD vm86_flags, vm86_cs,vm86_ip; |
LIN_ADDR vm86_stackPtr; |
DWORD *IRQTable_entry; |
|
if (service < 0x10 || in == NULL) |
return -1; |
|
if (service < 0x10 || in == NULL) return -1; |
/* Setup the stack frame */ |
vm86_tmpAddr = (DWORD) (vm86_stack); |
vm86_tmpAddr = (DWORD)(vm86_stack); |
vm86_TSS.t.ss = (vm86_tmpAddr & 0xFF000) >> 4; |
vm86_TSS.t.ebp = vm86_TSS.t.esp = (vm86_tmpAddr & 0x0FFF) |
+ VM86_STACK_SIZE - 6; |
+ VM86_STACK_SIZE - 6; |
/* Build an iret stack frame which returns to vm86_iretAddress */ |
vm86_tmpAddr = (DWORD) (vm86_iretAddress); |
vm86_tmpAddr = (DWORD)(vm86_iretAddress); |
vm86_cs = (vm86_tmpAddr & 0xFF000) >> 4; |
vm86_ip = (vm86_tmpAddr & 0xFFF); |
vm86_flags = 0; /* CPU_FLAG_VM | CPU_FLAG_IOPL; */ |
vm86_flags = 0; /* CPU_FLAG_VM | CPU_FLAG_IOPL; */ |
vm86_stackPtr = vm86_stack + VM86_STACK_SIZE; |
lmempokew(vm86_stackPtr - 6, vm86_ip); |
lmempokew(vm86_stackPtr - 4, vm86_cs); |
lmempokew(vm86_stackPtr - 2, vm86_flags); |
lmempokew(vm86_stackPtr-6,vm86_ip); |
lmempokew(vm86_stackPtr-4,vm86_cs); |
lmempokew(vm86_stackPtr-2,vm86_flags); |
#ifdef __LL_DEBUG__ |
message("Stack: %lx SS: %lx SP: %lx\n", |
vm86_tmpAddr + VM86_STACK_SIZE, (DWORD) vm86_TSS.t.ss, |
vm86_TSS.t.esp); |
vm86_tmpAddr + VM86_STACK_SIZE,(DWORD)vm86_TSS.t.ss,vm86_TSS.t.esp); |
#endif |
/* Wanted VM86 mode + IOPL = 3! */ |
vm86_TSS.t.eflags = CPU_FLAG_VM | CPU_FLAG_IOPL; |
/* Preload some standard values into the registers */ |
vm86_TSS.t.ss0 = X_FLATDATA_SEL; |
vm86_TSS.t.esp0 = (DWORD) & (vm86_stack0[VM86_STACK_SIZE - 1]); |
|
|
vm86_TSS.t.esp0 = (DWORD)&(vm86_stack0[VM86_STACK_SIZE-1]); |
|
|
#ifdef __DUMB_CODE__ |
vm86_TSS.t.cs = ((DWORD) (vm86_code) & 0xFFFF0) >> 4; |
vm86_TSS.t.eip = ((DWORD) (vm86_code) & 0x000F); |
vm86_TSS.t.cs = ((DWORD)(vm86_code) & 0xFFFF0) >> 4; |
vm86_TSS.t.eip = ((DWORD)(vm86_code) & 0x000F); |
#ifdef __LL_DEBUG_ |
message("(DUMB CODE) CS:%x IP:%x/%x\n", |
(DWORD) vm86_TSS.t.cs, vm86_TSS.t.eip, &prova86); |
(DWORD)vm86_TSS.t.cs,vm86_TSS.t.eip,&prova86); |
message("(DUMB CODE) Go...\n"); |
#endif |
vm86_TSS.t.back_link = ll_context_save(); |
279,44 → 285,41 |
#endif |
#else |
/* Copy the parms from the X_*REGS structures in the vm86 TSS */ |
vm86_TSS.t.eax = (DWORD) in->x.ax; |
vm86_TSS.t.ebx = (DWORD) in->x.bx; |
vm86_TSS.t.ecx = (DWORD) in->x.cx; |
vm86_TSS.t.edx = (DWORD) in->x.dx; |
vm86_TSS.t.esi = (DWORD) in->x.si; |
vm86_TSS.t.edi = (DWORD) in->x.di; |
vm86_TSS.t.eax = (DWORD)in->x.ax; |
vm86_TSS.t.ebx = (DWORD)in->x.bx; |
vm86_TSS.t.ecx = (DWORD)in->x.cx; |
vm86_TSS.t.edx = (DWORD)in->x.dx; |
vm86_TSS.t.esi = (DWORD)in->x.si; |
vm86_TSS.t.edi = (DWORD)in->x.di; |
/* IF Segment registers are required, copy them... */ |
if (s != NULL) { |
vm86_TSS.t.es = (WORD) s->es; |
vm86_TSS.t.ds = (WORD) s->ds; |
vm86_TSS.t.es = (WORD)s->es; |
vm86_TSS.t.ds = (WORD)s->ds; |
} else { |
vm86_TSS.t.ds = vm86_TSS.t.ss; |
vm86_TSS.t.es = vm86_TSS.t.ss; |
vm86_TSS.t.ds = vm86_TSS.t.ss; |
vm86_TSS.t.es = vm86_TSS.t.ss; |
} |
vm86_TSS.t.gs = vm86_TSS.t.ss; |
vm86_TSS.t.fs = vm86_TSS.t.ss; |
vm86_TSS.t.gs = vm86_TSS.t.ss; |
vm86_TSS.t.fs = vm86_TSS.t.ss; |
/* Execute the BIOS call, fetching the CS:IP of the real interrupt |
* handler from 0:0 (DOS irq table!) |
*/ |
IRQTable_entry = (void *) (0L); |
vm86_TSS.t.cs = ((IRQTable_entry[service]) & 0xFFFF0000) >> 16; |
IRQTable_entry = (void *)(0L); |
vm86_TSS.t.cs= ((IRQTable_entry[service]) & 0xFFFF0000) >> 16; |
vm86_TSS.t.eip = ((IRQTable_entry[service]) & 0x0000FFFF); |
#ifdef __LL_DEBUG__ |
message("CS:%hx IP:%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip); |
#ifdef __LL_DEBUG__ |
message("CS:%x IP:%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip); |
#endif |
/* Let's use the ll standard call... */ |
vm86_TSS.t.back_link = ll_context_save(); |
ll_context_load(X_VM86_TSS); |
#ifdef __LL_DEBUG__ |
#ifdef __LL_DEBUG__ |
message("I am back...\n"); |
message("TSS CS=%hx IP=%lx\n", vm86_TSS.t.cs, vm86_TSS.t.eip); |
{ |
char *xp = (char *) (vm86_iretAddress + 0xe); |
message("PM reentry linear address=%p\n", vm86_iretAddress); |
message("Executing code: %x ", (unsigned char) (*xp)); |
xp++; |
message("%x\n", (unsigned char) (*xp)); |
} |
{ char *xp = (char *)(vm86_iretAddress + 0xe); |
message("PM reentry linear address=%p\n", vm86_iretAddress); |
message("Executing code: %x ",(unsigned char)(*xp)); xp++; |
message("%x\n",(unsigned char)(*xp));} |
#endif |
/* Send back in the X_*REGS structure the value obtained with |
* the real-mode interrupt call |
332,26 → 335,26 |
out->x.cflag = (WORD)vm86_TSS.t.eflags; |
*/ |
#ifdef __LL_DEBUG__ |
message("%x\n", (WORD) * (GLOBesp)); |
message("%x\n", (WORD) * (GLOBesp + 1)); |
/*EDI*/ message("%x\n", (WORD) * (GLOBesp + 2)); |
/*ESI*/ message("%x\n", (WORD) * (GLOBesp + 3)); |
/*EBP*/ message("%x\n", (WORD) * (GLOBesp + 4)); |
/*ESP*/ message("%x\n", (WORD) * (GLOBesp + 5)); |
/*EBX*/ message("%x\n", (WORD) * (GLOBesp + 6)); |
/*EDX*/ |
#error Fix the following: use global_regs->xxx ??? |
message("%x\n", (WORD)*(GLOBesp)); |
message("%x\n", (WORD)*(GLOBesp+1)); /*EDI*/ |
message("%x\n", (WORD)*(GLOBesp+2)); /*ESI*/ |
message("%x\n", (WORD)*(GLOBesp+3)); /*EBP*/ |
message("%x\n", (WORD)*(GLOBesp+4)); /*ESP*/ |
message("%x\n", (WORD)*(GLOBesp+5)); /*EBX*/ |
message("%x\n", (WORD)*(GLOBesp+6)); /*EDX*/ |
#endif |
out->x.ax = (WORD) * (GLOBesp + 8); |
out->x.bx = (WORD) * (GLOBesp + 5); |
out->x.cx = (WORD) * (GLOBesp + 7); |
out->x.dx = (WORD) * (GLOBesp + 6); |
out->x.si = (WORD) * (GLOBesp + 2); |
out->x.di = (WORD) * (GLOBesp + 1); |
out->x.cflag = (WORD) * (GLOBesp); |
out->x.ax = global_regs->eax; |
out->x.bx = global_regs->ebx; |
out->x.cx = global_regs->ecx; |
out->x.dx = global_regs->edx; |
out->x.si = global_regs->esi; |
out->x.di = global_regs->edi; |
out->x.cflag = global_regs->flags; |
} |
if (s != NULL) { |
s->es = vm86_TSS.t.es; |
s->ds = vm86_TSS.t.ds; |
s->es = vm86_TSS.t.es; |
s->ds = vm86_TSS.t.ds; |
} |
#endif |
return 1; |