Merge branch 'master' of [email protected]:acess2
[tpg/acess2.git] / Kernel / arch / x86 / vm8086.c
index abc08dc..1816eac 100644 (file)
 #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;

UCC git Repository :: git.ucc.asn.au