X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Kernel%2Farch%2Fx86%2Fvm8086.c;h=1816eacf1c1f5f98a8015986079ba37d1635f040;hb=5beb98670f040b2d4e697e4d8690cd46d2d30cf3;hp=abc08dce9f618b4d23602062aee182fe96ac3c19;hpb=049de1f2533477716a12a708c097b199eaa8fb6c;p=tpg%2Facess2.git diff --git a/Kernel/arch/x86/vm8086.c b/Kernel/arch/x86/vm8086.c index abc08dce..1816eacf 100644 --- a/Kernel/arch/x86/vm8086.c +++ b/Kernel/arch/x86/vm8086.c @@ -13,10 +13,14 @@ #define VM8086_STACK_OFS 0x0AFE enum eVM8086_Opcodes { - VM8086_OP_PUSHF = 0x9C, - VM8086_OP_POPF = 0x9D, - VM8086_OP_INT_I = 0xCD, - VM8086_OP_IRET = 0xCF + VM8086_OP_PUSHF = 0x9C, + VM8086_OP_POPF = 0x9D, + VM8086_OP_INT_I = 0xCD, + VM8086_OP_IRET = 0xCF, + VM8086_OP_IN_AD = 0xEC, + VM8086_OP_IN_ADX = 0xED, + VM8086_OP_OUT_AD = 0xEE, + VM8086_OP_OUT_ADX = 0xEF }; #define VM8086_PAGES_PER_INST 4 @@ -43,13 +47,16 @@ MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL); tSpinlock glVM8086_Process; tPID gVM8086_WorkerPID; tTID gVM8086_CallingThread; -tVM8086 * volatile gpVM8086_State; +tVM8086 * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions // === FUNCTIONS === int VM8086_Install(char **Arguments) { tPID pid; + // Lock to avoid race conditions + LOCK( &glVM8086_Process ); + // Create BIOS Call process pid = Proc_Clone(NULL, CLONE_VM); if(pid == -1) @@ -69,10 +76,10 @@ int VM8086_Install(char **Arguments) // Map ROM Area for(i=0xA0;i<0x100;i++) { MM_Map( i * 0x1000, i * 0x1000 ); - MM_SetFlags( i * 0x1000, MM_PFLAG_RO, MM_PFLAG_RO ); // Set Read Only + //MM_SetFlags( i * 0x1000, MM_PFLAG_RO, MM_PFLAG_RO ); // Set Read Only } MM_Map( 0, 0 ); // IVT / BDA - for(i=0x70;i<0x80;i++) { + for(i=0x10;i<0x9F;i++) { MM_Map( i * 0x1000, i * 0x1000 ); MM_DerefPhys( i * 0x1000 ); } MM_Map( 0x9F000, 0x9F000 ); // Stack / EBDA @@ -137,6 +144,11 @@ void VM8086_GPF(tRegs *Regs) if(Regs->eip == VM8086_MAGIC_IP && Regs->cs == VM8086_MAGIC_CS && Threads_GetPID() == gVM8086_WorkerPID) { + if( gpVM8086_State == (void*)-1 ) { + Log_Log("VM8086", "Worker thread ready and waiting"); + RELEASE( &glVM8086_Process ); // Release lock obtained in VM8086_Install + gpVM8086_State = NULL; + } if( gpVM8086_State ) { gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx; gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx; @@ -155,7 +167,7 @@ void VM8086_GPF(tRegs *Regs) //Log_Log("VM8086", "gpVM8086_State = %p", gpVM8086_State); } - //Log_Log("VM8086", "We have a task"); + //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; Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS; @@ -174,7 +186,7 @@ void VM8086_GPF(tRegs *Regs) return ; } - opcode = *(Uint8*)( KERNEL_BASE + (Regs->cs*16) + (Regs->eip) ); + opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip) ); Regs->eip ++; switch(opcode) { @@ -211,7 +223,7 @@ void VM8086_GPF(tRegs *Regs) } break; - case 0xCF: //IRET + 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; #if TRACE_EMU @@ -219,6 +231,69 @@ void VM8086_GPF(tRegs *Regs) #endif break; + + case VM8086_OP_IN_AD: //IN AL, DX + 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); + #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); + #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); + #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); + #endif + break; + + // TODO: Decide on allowing VM8086 Apps to enable/disable interrupts + case 0xFA: //CLI + break; + case 0xFB: //STI + break; + + case 0x66: + opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip&0xFFFF)); + 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); + #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); + #endif + break; + default: + Log_Error("VM8086", "Error - Unknown opcode 66 %02x caused a GPF at %04x:%04x", + Regs->cs, Regs->eip, + opcode + ); + // Force an end to the call + Regs->cs = VM8086_MAGIC_CS; + Regs->eip = VM8086_MAGIC_IP; + break; + } + break; + default: Log_Error("VM8086", "Error - Unknown opcode %02x caused a GPF at %04x:%04x", opcode, Regs->cs, Regs->eip); @@ -252,23 +327,25 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) { int i, j, base = 0; int nBlocks, rem; - Uint32 bmp; Size = (Size + 127) & ~127; - nBlocks = Size >> 7; + nBlocks = Size / 128; if(Size > 4096) return NULL; for( i = 0; i < VM8086_PAGES_PER_INST; i++ ) { if( State->Internal->AllocatedPages[i].VirtBase == 0 ) continue; - bmp = State->Internal->AllocatedPages[i].Bitmap; + + + //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap); + rem = nBlocks; base = 0; // Scan the bitmap for a free block - for( j = 0; j < 32-nBlocks; j++ ) { - if( bmp & (1 << j) ) { - base = 0; + for( j = 0; j < 32; j++ ) { + if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) { + base = j; rem = nBlocks; } else { @@ -279,6 +356,7 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) State->Internal->AllocatedPages[i].Bitmap |= 1 << (base + j); *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16 + base * 8; *Offset = 0; + //Log_Debug("VM8086", "Allocated at #%i,%04x", i, base*128); return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 ); } } @@ -302,6 +380,7 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) for( j = 0; j < nBlocks; j++ ) State->Internal->AllocatedPages[i].Bitmap |= 1 << j; + //Log_Debug("VM8086", "AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap); *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16; *Offset = 0; return (void*) State->Internal->AllocatedPages[i].VirtBase;