X-Git-Url: https://git.ucc.asn.au/?p=tpg%2Facess2.git;a=blobdiff_plain;f=Kernel%2Farch%2Fx86%2Fvm8086.c;h=6d60d9b141f82227feec3da393257f982cf0b19a;hp=8ef7453e26818c62ba1e2644175b8b12d8d82147;hb=c205f388f8722a5d73f71ee98b0232444c5c7e9d;hpb=60149f3ea48a795f9fbb15149e87d3a41aa136bf diff --git a/Kernel/arch/x86/vm8086.c b/Kernel/arch/x86/vm8086.c index 8ef7453e..6d60d9b1 100644 --- a/Kernel/arch/x86/vm8086.c +++ b/Kernel/arch/x86/vm8086.c @@ -2,6 +2,7 @@ * Acess2 VM8086 Driver * - By John Hodge (thePowersGang) */ +#define DEBUG 0 #include #include #include @@ -13,15 +14,20 @@ #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_IN_AD = 0xEC, - VM8086_OP_IN_ADX= 0xED + 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 +#define VM8086_BLOCKSIZE 128 +#define VM8086_BLOCKCOUNT ((0x9F000-0x10000)/VM8086_BLOCKSIZE) + // === IMPORTS === int Proc_Clone(Uint *Err, Uint Flags); @@ -38,20 +44,24 @@ struct sVM8086_InternalData // === PROTOTYPES === int VM8086_Install(char **Arguments); void VM8086_GPF(tRegs *Regs); -tVM8086 *VM8086_Init(void); +//tVM8086 *VM8086_Init(void); // === GLOBALS === MODULE_DEFINE(0, 0x100, VM8086, VM8086_Install, NULL, NULL); -tSpinlock glVM8086_Process; +tMutex glVM8086_Process; tPID gVM8086_WorkerPID; tTID gVM8086_CallingThread; -tVM8086 * volatile gpVM8086_State; +tVM8086 volatile * volatile gpVM8086_State = (void*)-1; // Set to -1 to avoid race conditions +Uint32 gaVM8086_MemBitmap[VM8086_BLOCKCOUNT/32]; // === FUNCTIONS === int VM8086_Install(char **Arguments) { tPID pid; + // Lock to avoid race conditions + Mutex_Acquire( &glVM8086_Process ); + // Create BIOS Call process pid = Proc_Clone(NULL, CLONE_VM); if(pid == -1) @@ -61,8 +71,8 @@ int VM8086_Install(char **Arguments) } if(pid == 0) { - Uint *stacksetup; // Initialising Stack - Uint16 *rmstack; // Real Mode Stack + Uint * volatile stacksetup; // Initialising Stack + Uint16 * volatile rmstack; // Real Mode Stack int i; // Set Image Name @@ -74,11 +84,21 @@ int VM8086_Install(char **Arguments) //MM_SetFlags( i * 0x1000, MM_PFLAG_RO, MM_PFLAG_RO ); // Set Read Only } MM_Map( 0, 0 ); // IVT / BDA - for(i=0x10;i<0x9F;i++) { - MM_Map( i * 0x1000, i * 0x1000 ); MM_DerefPhys( i * 0x1000 ); + // 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 + if(MM_GetRefCount(i*0x1000)) + MM_DerefPhys( i * 0x1000 ); // Phys setup } MM_Map( 0x9F000, 0x9F000 ); // Stack / EBDA - MM_Allocate( 0x100000 ); // System Stack / Stub + // System Stack / Stub + if( MM_Allocate( 0x100000 ) == 0 ) { + Log_Error("VM8086", "Unable to allocate memory for stack/stub"); + gVM8086_WorkerPID = 0; + Threads_Exit(0, 1); + } *(Uint8*)(0x100000) = VM8086_OP_IRET; *(Uint8*)(0x100001) = 0x07; // POP ES @@ -86,32 +106,32 @@ int VM8086_Install(char **Arguments) *(Uint8*)(0x100003) = 0xCB; // RET FAR rmstack = (Uint16*)(VM8086_STACK_SEG*16 + VM8086_STACK_OFS); - *rmstack-- = 0xFFFF; //CS - *rmstack-- = 0x0010; //IP + rmstack--; *rmstack = 0xFFFF; //CS + rmstack--; *rmstack = 0x0010; //IP // Setup Stack stacksetup = (Uint*)0x101000; - *--stacksetup = VM8086_STACK_SEG; // GS - *--stacksetup = VM8086_STACK_SEG; // FS - *--stacksetup = VM8086_STACK_SEG; // DS - *--stacksetup = VM8086_STACK_SEG; // ES - *--stacksetup = VM8086_STACK_SEG; // SS - *--stacksetup = VM8086_STACK_OFS-2; // SP - *--stacksetup = 0x20202; // FLAGS - *--stacksetup = 0xFFFF; // CS - *--stacksetup = 0x10; // IP - *--stacksetup = 0xAAAA; // AX - *--stacksetup = 0xCCCC; // CX - *--stacksetup = 0xDDDD; // DX - *--stacksetup = 0xBBBB; // BX - *--stacksetup = 0x5454; // SP - *--stacksetup = 0xB4B4; // BP - *--stacksetup = 0x5151; // SI - *--stacksetup = 0xD1D1; // DI - *--stacksetup = 0x20|3; // DS - Kernel - *--stacksetup = 0x20|3; // ES - Kernel - *--stacksetup = 0x20|3; // FS - *--stacksetup = 0x20|3; // GS + stacksetup--; *stacksetup = VM8086_STACK_SEG; // GS + stacksetup--; *stacksetup = VM8086_STACK_SEG; // FS + stacksetup--; *stacksetup = VM8086_STACK_SEG; // DS + stacksetup--; *stacksetup = VM8086_STACK_SEG; // ES + stacksetup--; *stacksetup = VM8086_STACK_SEG; // SS + stacksetup--; *stacksetup = VM8086_STACK_OFS-2; // SP + stacksetup--; *stacksetup = 0x20202; // FLAGS + stacksetup--; *stacksetup = 0xFFFF; // CS + stacksetup--; *stacksetup = 0x10; // IP + stacksetup--; *stacksetup = 0xAAAA; // AX + stacksetup--; *stacksetup = 0xCCCC; // CX + stacksetup--; *stacksetup = 0xDDDD; // DX + stacksetup--; *stacksetup = 0xBBBB; // BX + stacksetup--; *stacksetup = 0x5454; // SP + stacksetup--; *stacksetup = 0xB4B4; // BP + stacksetup--; *stacksetup = 0x5151; // SI + stacksetup--; *stacksetup = 0xD1D1; // DI + stacksetup--; *stacksetup = 0x20|3; // DS - Kernel + stacksetup--; *stacksetup = 0x20|3; // ES - Kernel + stacksetup--; *stacksetup = 0x20|3; // FS + stacksetup--; *stacksetup = 0x20|3; // GS __asm__ __volatile__ ( "mov %%eax,%%esp;\n\t" // Set stack pointer "pop %%gs;\n\t" @@ -125,7 +145,13 @@ int VM8086_Install(char **Arguments) gVM8086_WorkerPID = pid; Log_Log("VM8086", "gVM8086_WorkerPID = %i", pid); - Threads_Yield(); // Yield to allow the child to initialise + while( gpVM8086_State != NULL ) + Threads_Yield(); // Yield to allow the child to initialise + + // Worker killed itself + if( gVM8086_WorkerPID != pid ) { + return MODULE_ERR_MISC; + } return MODULE_ERR_OK; } @@ -139,6 +165,13 @@ 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"); + gpVM8086_State = NULL; + Mutex_Release( &glVM8086_Process ); // Release lock obtained in VM8086_Install + } + //Log_Log("VM8086", "gpVM8086_State = %p, gVM8086_CallingThread = %i", + // gpVM8086_State, gVM8086_CallingThread); if( gpVM8086_State ) { gpVM8086_State->AX = Regs->eax; gpVM8086_State->CX = Regs->ecx; gpVM8086_State->DX = Regs->edx; gpVM8086_State->BX = Regs->ebx; @@ -146,6 +179,7 @@ void VM8086_GPF(tRegs *Regs) gpVM8086_State->SI = Regs->esi; gpVM8086_State->DI = Regs->edi; gpVM8086_State->DS = Regs->ds; gpVM8086_State->ES = Regs->es; gpVM8086_State = NULL; + // Wake the caller Threads_WakeTID(gVM8086_CallingThread); } @@ -158,12 +192,12 @@ void VM8086_GPF(tRegs *Regs) } //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; - Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP; - Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS; - Regs->esp -= 2; *(Uint16*)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_CS; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = VM8086_MAGIC_IP; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->CS; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->IP; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->DS; + Regs->esp -= 2; *(Uint16*volatile)( (Regs->ss<<4) + (Regs->esp&0xFFFF) ) = gpVM8086_State->ES; // Set Registers Regs->eip = 0x11; Regs->cs = 0xFFFF; @@ -176,7 +210,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) { @@ -202,8 +236,8 @@ 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->cs; - Regs->esp -= 2; *(Uint16*)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip; + Regs->esp -= 2; *(Uint16*volatile)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->cs; + Regs->esp -= 2; *(Uint16*volatile)( Regs->ss*16 + (Regs->esp&0xFFFF) ) = Regs->eip; Regs->cs = *(Uint16*)(4*id + 2); Regs->eip = *(Uint16*)(4*id); @@ -237,13 +271,13 @@ void VM8086_GPF(tRegs *Regs) #endif break; - case 0xEE: //OUT DX, AL + 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 0xEF: //OUT DX, AX + 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); @@ -257,8 +291,31 @@ void VM8086_GPF(tRegs *Regs) break; case 0x66: - Log_Warning("VM8086", "Code at %04x:%04x attempted to use an operand override, ignored", - Regs->cs, Regs->eip); + 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: @@ -312,20 +369,20 @@ void *VM8086_Allocate(tVM8086 *State, int Size, Uint16 *Segment, Uint16 *Offset) // Scan the bitmap for a free block for( j = 0; j < 32; j++ ) { if( State->Internal->AllocatedPages[i].Bitmap & (1 << j) ) { - base = j; + base = j+1; rem = nBlocks; } - else { - rem --; - 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; - *Offset = 0; - //Log_Debug("VM8086", "Allocated at #%i,%04x", i, base*128); - return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 ); - } + + rem --; + 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; + *Offset = 0; + LOG("Allocated at #%i,%04x", i, base*128); + LOG(" - %x:%x", *Segment, *Offset); + return (void*)( State->Internal->AllocatedPages[i].VirtBase + base * 128 ); } } } @@ -347,9 +404,10 @@ 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); + LOG("AllocatedPages[%i].Bitmap = 0b%b", i, State->Internal->AllocatedPages[i].Bitmap); *Segment = State->Internal->AllocatedPages[i].PhysAddr / 16; *Offset = 0; + LOG(" - %x:%x", *Segment, *Offset); return (void*) State->Internal->AllocatedPages[i].VirtBase; } @@ -363,13 +421,13 @@ void VM8086_Int(tVM8086 *State, Uint8 Interrupt) State->IP = *(Uint16*)(KERNEL_BASE+4*Interrupt); State->CS = *(Uint16*)(KERNEL_BASE+4*Interrupt+2); - LOCK( &glVM8086_Process ); + Mutex_Acquire( &glVM8086_Process ); gpVM8086_State = State; gVM8086_CallingThread = Threads_GetTID(); Threads_WakeTID( gVM8086_WorkerPID ); - while( gpVM8086_State != NULL ) - Threads_Sleep(); + Threads_Sleep(); + while( gpVM8086_State != NULL ) Threads_Sleep(); - RELEASE( &glVM8086_Process ); + Mutex_Release( &glVM8086_Process ); }