X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FKernel%2Farch%2Fx86%2Fvm8086.c;h=f1b50059989a0590d0871a35b296d512f5912be1;hb=14d0ba44433f0f828aff710184fd3c597ab73999;hp=61348622ceeacf5a7d8bdc7dcc957b423db47ea0;hpb=51ab5f489bc356940c95cc936fd0508e8f07ea97;p=tpg%2Facess2.git diff --git a/KernelLand/Kernel/arch/x86/vm8086.c b/KernelLand/Kernel/arch/x86/vm8086.c index 61348622..f1b50059 100644 --- a/KernelLand/Kernel/arch/x86/vm8086.c +++ b/KernelLand/Kernel/arch/x86/vm8086.c @@ -1,6 +1,9 @@ /* - * Acess2 VM8086 Driver + * Acess2 Kernel (x86) * - By John Hodge (thePowersGang) + * + * vm8086.c + * - Virtual 8086 Mode Monitor */ #define DEBUG 0 #include @@ -10,6 +13,10 @@ #include // === CONSTANTS === +#define TRACE_EMU 0 + +#define VM8086_USER_BASE 0x1000 + #define VM8086_MAGIC_CS 0xFFFF #define VM8086_MAGIC_IP 0x0010 #define VM8086_STACK_SEG 0x9F00 @@ -31,13 +38,15 @@ enum eVM8086_Opcodes #define VM8086_BLOCKCOUNT ((0x9F000-0x10000)/VM8086_BLOCKSIZE) // === TYPES === +struct sVM8086_InternalPages +{ + Uint32 Bitmap; // 32 sections = 128 byte blocks + char *VirtBase; + tPAddr PhysAddr; +}; struct sVM8086_InternalData { - struct { - Uint32 Bitmap; // 32 sections = 128 byte blocks - tVAddr VirtBase; - tPAddr PhysAddr; - } AllocatedPages[VM8086_PAGES_PER_INST]; + struct sVM8086_InternalPages AllocatedPages[VM8086_PAGES_PER_INST]; }; // === PROTOTYPES === @@ -54,20 +63,19 @@ tPID gVM8086_WorkerPID; tTID gVM8086_CallingThread; tVM8086 volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32]; + int gbVM8086_ShadowIF = 0; // === FUNCTIONS === int VM8086_Install(char **Arguments) { - tPID pid; - Semaphore_Init(&gVM8086_TasksToDo, 0, 10, "VM8086", "TasksToDo"); // Lock to avoid race conditions Mutex_Acquire( &glVM8086_Process ); // Create BIOS Call process - pid = Proc_Clone(CLONE_VM); - Log_Debug("VM8086", "pid = %i", pid); + tPID pid = Proc_Clone(CLONE_VM); + LOG("pid = %i", pid); if(pid == -1) { Log_Error("VM8086", "Unable to clone kernel into VM8086 worker"); @@ -77,29 +85,31 @@ int VM8086_Install(char **Arguments) { Uint * volatile stacksetup; // Initialising Stack Uint16 * volatile rmstack; // Real Mode Stack - int i; - Log_Debug("VM8086", "Initialising worker"); + LOG("Initialising worker"); // Set Image Name Threads_SetName("VM8086"); // Map ROM Area - for(i=0xA0;i<0x100;i++) { - MM_Map( i * 0x1000, i * 0x1000 ); + for(unsigned int i = 0xA0;i<0x100;i++) { + MM_RefPhys(i * 0x1000); + MM_Map( (void*)(i * 0x1000), i * 0x1000 ); + } + MM_RefPhys(0); + MM_Map( (void*)0, 0 ); // IVT / BDA + if( MM_GetRefCount(0x00000) > 2 ) { + Log_Notice("VM8086", "Ok, who's touched the IVT? (%i)", + MM_GetRefCount(0x00000)); } - MM_Map( 0, 0 ); // IVT / BDA - // Map (but allow allocation) of 0x1000 - 0x9F000 - // - So much hack, it isn't funny - for(i=1;i<0x9F;i++) { - MM_Map( i * 0x1000, i * 0x1000 ); - MM_DerefPhys( i * 0x1000 ); // Above - while(MM_GetRefCount(i*0x1000)) - MM_DerefPhys( i * 0x1000 ); // Phys setup + MM_RefPhys(0x9F000); + MM_Map( (void*)0x9F000, 0x9F000 ); // Stack / EBDA + if( MM_GetRefCount(0x9F000) > 2 ) { + Log_Notice("VM8086", "And who's been playing with my EBDA? (%i)", + MM_GetRefCount(0x9F000)); } - MM_Map( 0x9F000, 0x9F000 ); // Stack / EBDA // System Stack / Stub - if( MM_Allocate( 0x100000 ) == 0 ) { + if( MM_Allocate( (void*)0x100000 ) == 0 ) { Log_Error("VM8086", "Unable to allocate memory for stack/stub"); gVM8086_WorkerPID = 0; Threads_Exit(0, 1); @@ -137,6 +147,7 @@ int VM8086_Install(char **Arguments) stacksetup--; *stacksetup = 0x20|3; // ES - Kernel stacksetup--; *stacksetup = 0x20|3; // FS stacksetup--; *stacksetup = 0x20|3; // GS + LOG("stacksetup = %p, entering vm8086"); __asm__ __volatile__ ( "mov %%eax,%%esp;\n\t" // Set stack pointer "pop %%gs;\n\t" @@ -151,6 +162,7 @@ int VM8086_Install(char **Arguments) gVM8086_WorkerPID = pid; // It's released when the GPF fires + LOG("Waiting for worker %i to start", gVM8086_WorkerPID); Mutex_Acquire( &glVM8086_Process ); Mutex_Release( &glVM8086_Process ); @@ -165,9 +177,12 @@ int VM8086_Install(char **Arguments) void VM8086_GPF(tRegs *Regs) { Uint8 opcode; + Uint16 newcs, newip; // Log_Log("VM8086", "GPF - %04x:%04x", Regs->cs, Regs->eip); - + + LOG("VM8086 GPF at %04x:%04x", Regs->cs, Regs->eip); + if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS && Threads_GetPID() == gVM8086_WorkerPID) { @@ -178,13 +193,25 @@ void VM8086_GPF(tRegs *Regs) } // Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i", // gpVM8086_State, gVM8086_CallingThread); - if( gpVM8086_State ) { + if( gpVM8086_State ) + { gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx; gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx; gpVM8086_State->BP = Regs->ebp; gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi; gpVM8086_State->DS = Regs->ds; gpVM8086_State->ES = Regs->es; + + LOG("gpVM8086_State = %p", gpVM8086_State); + LOG("gpVM8086_State->Internal = %p", gpVM8086_State->Internal); + for( Uint i = 0; i < VM8086_PAGES_PER_INST; i ++ ) + { + if( !gpVM8086_State->Internal->AllocatedPages[i].VirtBase ) + continue ; + MM_Deallocate( (tPage*)VM8086_USER_BASE + i ); + } + gpVM8086_State = NULL; + // Wake the caller Semaphore_Signal(&gVM8086_TaskComplete, 1); } @@ -193,6 +220,15 @@ void VM8086_GPF(tRegs *Regs) __asm__ __volatile__ ("sti"); Semaphore_Wait(&gVM8086_TasksToDo, 1); + for( Uint i = 0; i < VM8086_PAGES_PER_INST; i ++ ) + { + if( !gpVM8086_State->Internal->AllocatedPages[i].VirtBase ) + continue ; + MM_RefPhys( gpVM8086_State->Internal->AllocatedPages[i].PhysAddr ); + MM_Map( (tPage*)VM8086_USER_BASE + i, gpVM8086_State->Internal->AllocatedPages[i].PhysAddr ); + } + + //Log_Log("VM8086", "We have a task (%p)", gpVM8086_State); Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS; Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP; @@ -219,17 +255,24 @@ void VM8086_GPF(tRegs *Regs) case VM8086_OP_PUSHF: //PUSHF Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eflags & 0xFFFF; + if( gbVM8086_ShadowIF ) + *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) |= 0x200; + else + *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) &= ~0x200; #if TRACE_EMU - Log_Debug("VM8086", "Emulated PUSHF"); + Log_Debug("VM8086", "%04x:%04x Emulated PUSHF (value 0x%x)", + Regs->cs, Regs->eip-1, Regs->eflags & 0xFFFF); #endif break; case VM8086_OP_POPF: //POPF // Changing IF is not allowed Regs->eflags &= 0xFFFF0202; Regs->eflags |= *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); + gbVM8086_ShadowIF = !!(*(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) & 0x200); Regs->esp += 2; #if TRACE_EMU - Log_Debug("VM8086", "Emulated POPF"); + Log_Debug("VM8086", "%04x:%04x Emulated POPF (new value 0x%x)", + Regs->cs, Regs->eip-1, Regs->eflags & 0xFFFF); #endif break; @@ -239,23 +282,30 @@ void VM8086_GPF(tRegs *Regs) id = *(Uint8*)( Regs->cs*16 +(Regs->eip&0xFFFF)); Regs->eip ++; + Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eflags; Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs; Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip; - Regs->cs = *(Uint16*)(4*id + 2); - Regs->eip = *(Uint16*)(4*id); + newcs = *(Uint16*)(4*id + 2); + newip = *(Uint16*)(4*id); #if TRACE_EMU - Log_Debug("VM8086", "Emulated INT 0x%x", id); + Log_Debug("VM8086", "%04x:%04x Emulated INT 0x%x (%04x:%04x) - AX=%04x,BX=%04x", + Regs->cs, Regs->eip-2, id, newcs, newip, Regs->eax, Regs->ebx); #endif + Regs->cs = newcs; + Regs->eip = newip; } break; case VM8086_OP_IRET: //IRET - Regs->eip = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2; - Regs->cs = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2; + newip = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2; + newcs = *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ); Regs->esp += 2; #if TRACE_EMU - Log_Debug("VM8086", "IRET to %04x:%04x", Regs->cs, Regs->eip); + Log_Debug("VM8086", "%04x:%04x IRET to %04x:%04x", + Regs->cs, Regs->eip-1, newcs, newip); #endif + Regs->cs = newcs; + Regs->eip = newip; break; @@ -263,55 +313,72 @@ void VM8086_GPF(tRegs *Regs) Regs->eax &= 0xFFFFFF00; Regs->eax |= inb(Regs->edx&0xFFFF); #if TRACE_EMU - Log_Debug("VM8086", "Emulated IN AL, DX (Port 0x%x)\n", Regs->edx&0xFFFF); + Log_Debug("VM8086", "%04x:%04x Emulated IN AL, DX (Port 0x%x [Val 0x%02x])", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax&0xFF); #endif break; case VM8086_OP_IN_ADX: //IN AX, DX Regs->eax &= 0xFFFF0000; Regs->eax |= inw(Regs->edx&0xFFFF); #if TRACE_EMU - Log_Debug("VM8086", "Emulated IN AX, DX (Port 0x%x)\n", Regs->edx&0xFFFF); + Log_Debug("VM8086", "%04x:%04x Emulated IN AX, DX (Port 0x%x [Val 0x%04x])", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax&0xFFFF); #endif break; case VM8086_OP_OUT_AD: //OUT DX, AL outb(Regs->edx&0xFFFF, Regs->eax&0xFF); #if TRACE_EMU - Log_Debug("VM8086", "Emulated OUT DX, AL (*0x%04x = 0x%02x)\n", Regs->edx&0xFFFF, Regs->eax&0xFF); + Log_Debug("VM8086", "%04x:%04x Emulated OUT DX, AL (*0x%04x = 0x%02x)", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax&0xFF); #endif break; case VM8086_OP_OUT_ADX: //OUT DX, AX outw(Regs->edx&0xFFFF, Regs->eax&0xFFFF); #if TRACE_EMU - Log_Debug("VM8086", "Emulated OUT DX, AX (*0x%04x = 0x%04x)\n", Regs->edx&0xFFFF, Regs->eax&0xFFFF); + Log_Debug("VM8086", "%04x:%04x Emulated OUT DX, AX (*0x%04x = 0x%04x)", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax&0xFFFF); #endif break; // TODO: Decide on allowing VM8086 Apps to enable/disable interrupts case 0xFA: //CLI + #if TRACE_EMU + Log_Debug("VM8086", "%04x:%04x Ignored CLI", + Regs->cs, Regs->eip); + #endif + gbVM8086_ShadowIF = 0; break; case 0xFB: //STI + #if TRACE_EMU + Log_Debug("VM8086", "%04x:%04x Ignored STI", + Regs->cs, Regs->eip); + #endif + gbVM8086_ShadowIF = 1; break; case 0x66: opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip&0xFFFF)); + Regs->eip ++; switch( opcode ) { case VM8086_OP_IN_ADX: //IN AX, DX Regs->eax = ind(Regs->edx&0xFFFF); #if TRACE_EMU - Log_Debug("VM8086", "Emulated IN EAX, DX (Port 0x%x)\n", Regs->edx&0xFFFF); + Log_Debug("VM8086", "%04x:%04x Emulated IN EAX, DX (Port 0x%x [Val 0x%08x])", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax); #endif break; case VM8086_OP_OUT_ADX: //OUT DX, AX outd(Regs->edx&0xFFFF, Regs->eax); #if TRACE_EMU - Log_Debug("VM8086", "Emulated OUT DX, EAX (*0x%04x = 0x%08x)\n", Regs->edx&0xFFFF, Regs->eax); + Log_Debug("VM8086", "%04x:%04x Emulated OUT DX, EAX (*0x%04x = 0x%08x)", + Regs->cs, Regs->eip-1, Regs->edx&0xFFFF, Regs->eax); #endif break; default: Log_Error("VM8086", "Error - Unknown opcode 66 %02x caused a GPF at %04x:%04x", - Regs->cs, Regs->eip, + Regs->cs, Regs->eip-2, opcode ); // Force an end to the call @@ -321,9 +388,18 @@ void VM8086_GPF(tRegs *Regs) } break; + case 0x0F: + opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip&0xFFFF)); + Log_Error("VM8086", "Error - Unknown opcode 0F %02x caused a GPF at %04x:%04x", + opcode, Regs->cs, Regs->eip); + // Force an end to the call + Regs->cs = VM8086_MAGIC_CS; + Regs->eip = VM8086_MAGIC_IP; + break; + default: Log_Error("VM8086", "Error - Unknown opcode %02x caused a GPF at %04x:%04x", - opcode, Regs->cs, Regs->eip); + opcode, Regs->cs, Regs->eip-1); // Force an end to the call Regs->cs = VM8086_MAGIC_CS; Regs->eip = VM8086_MAGIC_IP; @@ -344,14 +420,15 @@ tVM8086 *VM8086_Init(void) void VM8086_Free(tVM8086 *State) { - int i; - for( i = VM8086_PAGES_PER_INST; i --; ) + // TODO: Make sure the state isn't in use currently + for( Uint i = VM8086_PAGES_PER_INST; i --; ) MM_UnmapHWPages( State->Internal->AllocatedPages[i].VirtBase, 1); free(State); } void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) { + struct sVM8086_InternalPages *pages = State->Internal->AllocatedPages; int i, j, base = 0; int nBlocks, rem; @@ -362,16 +439,18 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) for( i = 0; i < VM8086_PAGES_PER_INST; i++ ) { - if( State->Internal->AllocatedPages[i].VirtBase == 0 ) continue; + if( pages[i].VirtBase == 0 ) continue; - - //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap); + //Log_Debug("VM8086", "pages[%i].Bitmap = 0b%b", i, pages[i].Bitmap); rem = nBlocks; base = 0; // Scan the bitmap for a free block - for( j = 0; j < 32; j++ ) { - if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) { + // - 32 blocks per page == 128 bytes per block == 8 segments + for( j = 0; j < 32; j++ ) + { + if( pages[i].Bitmap & (1 << j) ) + { base = j+1; rem = nBlocks; } @@ -380,12 +459,12 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) if(rem == 0) // Goodie, there's a gap { for( j = 0; j < nBlocks; j++ ) - State->Internal->AllocatedPages[i].Bitmap |= 1 << (base + j); - *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16 + base * 8; + pages[i].Bitmap |= 1 << (base + j); + *Segment = (VM8086_USER_BASE + i * 0x1000) / 16 + base * 8; *Offset = 0; - LOG("Allocated at #%i,%04x", i, base*128); + LOG("Allocated at #%i,%04x", i, base*8*16); LOG(" - %x:%x", *Segment, *Offset); - return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 ); + return pages[i].VirtBase + base * 8 * 16; } } } @@ -393,7 +472,7 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) // No pages with free space?, allocate a new one for( i = 0; i < VM8086_PAGES_PER_INST; i++ ) { - if( State->Internal->AllocatedPages[i].VirtBase == 0 ) break; + if( pages[i].VirtBase == 0 ) break; } // Darn, we can't allocate any more if( i == VM8086_PAGES_PER_INST ) { @@ -401,22 +480,40 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) return NULL; } - State->Internal->AllocatedPages[i].VirtBase = MM_AllocDMA( - 1, 20, &State->Internal->AllocatedPages[i].PhysAddr); - State->Internal->AllocatedPages[i].Bitmap = 0; + pages[i].VirtBase = MM_AllocDMA(1, -1, &pages[i].PhysAddr); + if( pages[i].VirtBase == 0 ) { + Log_Warning("VM8086", "Unable to allocate data page"); + return NULL; + } + pages[i].Bitmap = 0; + LOG("AllocatedPages[%i].VirtBase = %p", i, pages[i].VirtBase); + LOG("AllocatedPages[%i].PhysAddr = %P", i, pages[i].PhysAddr); for( j = 0; j < nBlocks; j++ ) - State->Internal->AllocatedPages[i].Bitmap |= 1 << j; - LOG("AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap); - *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16; + pages[i].Bitmap |= 1 << j; + LOG("AllocatedPages[%i].Bitmap = 0b%b", i, pages[i].Bitmap); + *Segment = (VM8086_USER_BASE + i * 0x1000) / 16; *Offset = 0; - LOG(" - %x:%x", *Segment, *Offset); - return (void*) State->Internal->AllocatedPages[i].VirtBase; + LOG(" - %04x:%04x", *Segment, *Offset); + return pages[i].VirtBase; } void *VM8086_GetPointer(tVM8086 *State, Uint16 Segment, Uint16 Offset) { - return (void*)( KERNEL_BASE + Segment*16 + Offset ); + Uint32 addr = Segment * 16 + Offset; + + if( VM8086_USER_BASE <= addr && addr < VM8086_USER_BASE + VM8086_PAGES_PER_INST*0x1000 ) + { + int pg = (addr - VM8086_USER_BASE) / 0x1000; + if( State->Internal->AllocatedPages[pg].VirtBase == 0) + return NULL; + else + return State->Internal->AllocatedPages[pg].VirtBase + (addr & 0xFFF); + } + else + { + return (void*)( KERNEL_BASE + addr ); + } } void VM8086_Int(tVM8086 *State, Uint8 Interrupt)