* Acess2 VM8086 Driver
* - By John Hodge (thePowersGang)
*/
+#define DEBUG 0
#include <acess.h>
#include <vm8086.h>
#include <modules.h>
+#include <hal_proc.h>
// === CONSTANTS ===
#define VM8086_MAGIC_CS 0xFFFF
};
#define VM8086_PAGES_PER_INST 4
-// === IMPORTS ===
- int Proc_Clone(Uint *Err, Uint Flags);
+#define VM8086_BLOCKSIZE 128
+#define VM8086_BLOCKCOUNT ((0x9F000-0x10000)/VM8086_BLOCKSIZE)
// === TYPES ===
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 * 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
- LOCK( &glVM8086_Process );
+ Mutex_Acquire( &glVM8086_Process );
// Create BIOS Call process
- pid = Proc_Clone(NULL, CLONE_VM);
+ pid = Proc_Clone(CLONE_VM);
if(pid == -1)
{
Log_Error("VM8086", "Unable to clone kernel into VM8086 worker");
Uint * volatile stacksetup; // Initialising Stack
Uint16 * volatile rmstack; // Real Mode Stack
int i;
-
+
// Set Image Name
Threads_SetName("VM8086");
-
+
+ Log_Debug("VM8086", "Mapping memory");
+
// 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
}
+ Log_Debug("VM8086", "ROM area mapped");
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
+ while(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);
+ }
+ Log_Debug("VM8086", "Mapped low memory");
*(Uint8*)(0x100000) = VM8086_OP_IRET;
*(Uint8*)(0x100001) = 0x07; // POP ES
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;
}
{
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;
+ 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;
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);
}
// 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 );
}
}
}
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;
}
{
State->IP = *(Uint16*)(KERNEL_BASE+4*Interrupt);
State->CS = *(Uint16*)(KERNEL_BASE+4*Interrupt+2);
+
+// Log_Debug("VM8086", "Software interrupt %i to %04x:%04x", Interrupt, State->CS, State->IP);
- 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 );
}