00001 /* ndk - [ vm86.c ] 00002 * 00003 * Contains code to handle vm86 tasks. 00004 * Currently being revamped (does not work). 00005 * 00006 * Please see: 00007 * /src/drivers/video/vesa/vesa.c 00008 * 00009 * (c)2002 dcipher / neuraldk 00010 * www.neuraldk.org 00011 */ 00012 00013 #include "vm86.h" 00014 00015 // page directory to use when calling bios ints 00016 pageDirectory *vm86PageDir; 00017 TSS vm86TSS; 00018 00019 void vm86Init(void) { 00020 vm86CreatePagingInfo(); 00021 vm86FillTSS(&vm86TSS, 0, 0, 0); 00022 createGate(&IDT, 0x81, (long)vm86IntHandler, SEL_P0_CODE, D_INT); 00023 } 00024 00025 void vm86CreatePagingInfo(void) { 00026 pageTable *pTable; 00027 long i; 00028 00029 // find 4kb aligned address for page directory 00030 vm86PageDir = (pageDirectory *)0x00092000; 00031 00032 // find 4kb aligned address for 1 page table 00033 pTable = (pageTable *)0x00093000; 00034 00035 // assign 1st page directory entry to page table 00036 vm86PageDir->pageTable[0] = (long)pTable | PAGE_PRESENT 00037 | PAGE_READ_WRITE 00038 | PAGE_P3_ACCESS; 00039 00040 // clear the rest of the page directory 00041 for(i = 1; i < 1024; i++) 00042 vm86PageDir->pageTable[i] = 0; 00043 00044 // assign the first page to the real mode idt 00045 pTable->pageAddr[0] = 0x00001000; 00046 00047 // and map the rest of the pages to their physical 00048 // equivalents 00049 for(i = 1; i < 1024; i++) { 00050 pTable->pageAddr[i] = (i * 4096) | PAGE_PRESENT 00051 | PAGE_READ_WRITE 00052 | PAGE_P3_ACCESS; 00053 } 00054 } 00055 00056 // the next two might be better placed in task.c 00057 void vm86FillTSS(TSS *tss, long eip, long p0_esp, long p3_esp) { 00058 tss->ldtr = 0; 00059 tss->fs = tss->gs = SEL_P3_DATA | 3; 00060 tss->ds = tss->es = SEL_P3_DATA | 3; 00061 tss->ss = SEL_P3_STACK | 3; 00062 tss->cs = SEL_P3_CODE | 3; 00063 tss->eflags = 0x00023202L | 1 << 18; // vm86, IOPL=3, STI, Alignment Check 00064 tss->esp = /*p0_esp;*/p3_esp; 00065 tss->eip = eip; 00066 tss->cr3 = getCR3(); 00067 00068 tss->esp0 = p0_esp; 00069 tss->ss0 = SEL_P0_STACK; 00070 00071 tss->link = 0; 00072 } 00073 00074 /* 00075 void vm86Int(long intNum, vm86Regs *regs) { 00076 // load registers with values in regs 00077 00078 // push interrupt number onto stack 00079 00080 // call real mode interrrupt interface 00081 00082 // copy registers back in regs 00083 } 00084 */ 00085 00086 /* 00087 // Call this interrupt (0x??) with the real mode int you wish to call 00088 // pushed onto the stack (or in the top bits of eax? real mode ints 00089 // wont use it anyway...). All registers are set up as if you were 00090 // calling that real mode interrupt. 00091 void vm86IntHandler(void) { 00092 // at this point: 00093 // an iret returns to vm86int function, or P3 app... 00094 // interrupt number is on stack (which one?) above cs:eip, eflags 00095 // currentTask->p3_stack... what if the kernel called? It doesn't 00096 // have a p3 stack... probably best to use high half of a register (eax?) 00097 00098 // save stack frame (where?) -- perhaps not needed 00099 00100 // add to stack frame 00101 // point to real mode interrupt, set vm86 = 1 00102 00103 // iret 00104 00105 // .... 00106 // control is passed to real mode int, in vm86 mode... 00107 // upon vm86 iret, transfer is given to gpf routine: 00108 00109 // get previous stack frame (again, from where?) 00110 // -- not needed... pmode return address is on the stack! 00111 00112 // change stack frame to point to this, set vm86 = 0 00113 // -- again, not needed? 00114 00115 // iret, returns to pmode function that called int 00116 } 00117 */