-BUILD_NUM = 1982
+BUILD_NUM = 2027
A_OBJ = start.ao main.o lib.o desctab.ao errors.o irq.o
A_OBJ += mm_phys.o mm_virt.o
-A_OBJ += proc.o time.o vm8086.o
+A_OBJ += proc.o proc.ao time.o vm8086.o
A_OBJ += kpanic.o
; IRQs
; - Timer
[global Isr240]
+[extern SchedulerBase]
Isr240:
push 0
jmp SchedulerBase
popa
add esp, 8 ; Error Code and ID
iret
-
-; --------------
-; Task Scheduler
-; --------------
-[extern Proc_Scheduler]
-SchedulerBase:
- pusha
- push ds
- push es
- push fs
- push gs
-
- mov ax, 0x10
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
-
- mov eax, [esp+12*4] ; CPU Number
- push eax ; Pus as argument
-
- call Proc_Scheduler
-
- add esp, 4 ; Remove Argument
-
- pop gs
- pop fs
- pop es
- pop ds
-
- mov dx, 0x20
- mov al, 0x20
- out dx, al ; ACK IRQ
- popa
- add esp, 4 ; CPU ID
- ; No Error code / int num
- iret
{
int i;
- // Some routines call this function twice, let's avoid that, shall we?
+ // This function is called by Panic(), but MM_PageFault and the
+ // CPU exception handers also call it, so let's not clear the screen
+ // twice
if( giKP_Pos ) return ;
// Restore VGA 0xB8000 text mode
for( j = 0; j < Number; j++ )
{
- MM_DerefPhys( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] );
+ MM_DerefPhys( gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] & ~0xFFF );
gaPageTable[ (HW_MAP_ADDR >> 12) + i + j ] = 0;
}
extern void Threads_Dump();
extern tThread *Threads_CloneTCB(Uint *Err, Uint Flags);
extern void Isr8(); // Double Fault
+extern void Proc_AlterUserReturnAddr();
// === PROTOTYPES ===
void ArchThreads_Init();
void Proc_ChangeStack();
int Proc_Clone(Uint *Err, Uint Flags);
void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP);
+void Proc_CallFaultHandler(tThread *Thread);
void Proc_Scheduler();
// === GLOBALS ===
return 0;
}
+/**
+ * \brief Calls a signal handler in user mode
+ * \note Used for signals
+ */
+void Proc_CallFaultHandler(tThread *Thread)
+{
+ // Rewinds the stack and calls the user function
+ // Never returns
+ __asm__ __volatile__ ("mov %0, %%ebp;\n\tcall Proc_AlterUserReturnAddr" :: "r"(Thread->FaultHandler));
+ for(;;);
+}
+
/**
* \fn void Proc_Scheduler(int CPU)
* \brief Swap current thread and clears dead threads
pop ebp\r
ret\r
\r
-[extern Proc_Clone]\r
-[extern Threads_Exit]\r
-[global SpawnTask]\r
-SpawnTask:\r
- ; Call Proc_Clone with Flags=0\r
- xor eax, eax\r
- push eax
- push eax\r
- call Proc_Clone\r
- add esp, 8 ; Remove arguments from stack\r
- \r
- test eax, eax\r
- jnz .parent\r
- \r
- ; In child, so now set up stack frame\r
- mov ebx, [esp+4] ; Child Function\r
- mov edx, [esp+8] ; Argument\r
- ; Child\r
- push edx ; Argument\r
- call ebx ; Function\r
- call Threads_Exit ; Kill Thread\r
- \r
-.parent:\r
- ret\r
-\r
[section .initpd]\r
[global gaInitPageDir]\r
[global gaInitPageTable]\r
#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
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)
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;
return ;
}
- opcode = *(Uint8*)( KERNEL_BASE + (Regs->cs*16) + (Regs->eip) );
+ opcode = *(Uint8*)( (Regs->cs*16) + (Regs->eip) );
Regs->eip ++;
switch(opcode)
{
#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);
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:
SYS_EXIT, // 0 - Kill this thread
SYS_CLONE, // 1 - Create a new thread
SYS_KILL, // 2 - Send a signal
- SYS_SIGNAL, // 3 - Set signal Handler
+ SYS_SETFAULTHANDLER, // 3 - Set signal Handler
SYS_YIELD, // 4 - Yield remainder of timestamp
SYS_SLEEP, // 5 - Sleep until messaged or signaled
SYS_WAIT, // 6 - Wait for a time or a message
};
static const char *cSYSCALL_NAMES[] = {
- "SYS_EXIT","SYS_CLONE","SYS_KILL","SYS_SIGNAL","SYS_YIELD","SYS_SLEEP",
+ "SYS_EXIT","SYS_CLONE","SYS_KILL","SYS_SETFAULTHANDLER","SYS_YIELD","SYS_SLEEP",
"SYS_WAIT","SYS_WAITTID","SYS_SETNAME","SYS_GETNAME","SYS_GETTID","SYS_GETPID",
"SYS_SETPRI","SYS_SENDMSG","SYS_GETMSG","SYS_GETTIME","SYS_SPAWN","SYS_EXECVE",
"SYS_LOADBIN","SYS_UNLOADBIN","SYS_LOADMOD","","","",
%define SYS_EXIT 0 ; Kill this thread
%define SYS_CLONE 1 ; Create a new thread
%define SYS_KILL 2 ; Send a signal
-%define SYS_SIGNAL 3 ; Set signal Handler
+%define SYS_SETFAULTHANDLER 3 ; Set signal Handler
%define SYS_YIELD 4 ; Yield remainder of timestamp
%define SYS_SLEEP 5 ; Sleep until messaged or signaled
%define SYS_WAIT 6 ; Wait for a time or a message
typedef struct sThread
{
// --- threads.c's
+ // 0
struct sThread *Next; //!< Next thread in list
tSpinlock IsLocked; //!< Thread's spinlock
volatile int Status; //!< Thread Status
int RetStatus; //!< Return Status
+ // 16
Uint TID; //!< Thread ID
Uint TGID; //!< Thread Group (Process)
Uint PTID; //!< Parent Thread ID
char *ThreadName; //!< Name of thread
// --- arch/proc.c's responsibility
+ // 40
//! Kernel Stack Base
tVAddr KernelStack;
+ // 44 (x86)
//! Memory Manager State
tMemoryState MemState;
+ // 48 (x86)
//! State on task switch
tTaskState SavedState;
// --- threads.c's
- int CurSignal; //!< Signal currently being handled (0 for none)
- tVAddr SignalHandlers[NSIG]; //!< Signal Handler List
- tTaskState SignalState; //!< Saved state for signal handler
+ // 60
+ int CurFaultNum; //!< Current fault number, 0: none
+ tVAddr FaultHandler; //!< Fault Handler
tMsg * volatile Messages; //!< Message Queue
tMsg *LastMessage; //!< Last Message (speeds up insertion)
extern int Threads_SetUID(Uint *errno, tUID ID);
extern tGID Threads_GetGID();
extern int Threads_SetGID(Uint *errno, tGID ID);
+extern int Threads_SetFaultHandler(Uint Handler);
// === PROTOTYPES ===
int Syscall_ValidString(Uint Addr);
// -- Yield current timeslice
case SYS_YIELD: Threads_Yield(); break;
+ // -- Set Error Handler
+ case SYS_SETFAULTHANDLER:
+ Threads_SetFaultHandler(Regs->Arg1);
+ break;
+
// -- Clone the current thread
case SYS_CLONE:
// Call clone system call
SYS_EXIT Kill this thread
SYS_CLONE Create a new thread
SYS_KILL Send a signal
-SYS_SIGNAL Set signal Handler
+SYS_SETFAULTHANDLER Set signal Handler
SYS_YIELD Yield remainder of timestamp
SYS_SLEEP Sleep until messaged or signaled
SYS_WAIT Wait for a time or a message
extern void Proc_Start();
extern tThread *Proc_GetCurThread();
extern int Proc_Clone(Uint *Err, Uint Flags);
+extern void Proc_CallFaultHandler(tThread *Thread);
// === PROTOTYPES ===
void Threads_Init();
{0}, // Saved State
{0}, // VM State
- 0, {0}, {0}, // Signal State
+ 0, 0, // Current Fault, Fault Handler
NULL, NULL, // Messages, Last Message
DEFAULT_QUANTUM, DEFAULT_QUANTUM, // Quantum, Remaining
new->NumTickets = cur->NumTickets;
// Set Signal Handlers
- new->CurSignal = 0;
- if(Flags & CLONE_VM)
- memset(new->SignalHandlers, 0, sizeof(new->SignalHandlers));
- else
- memcpy(new->SignalHandlers, cur->SignalHandlers, sizeof(new->SignalHandlers));
- memset(&new->SignalState, 0, sizeof(tTaskState));
+ new->CurFaultNum = 0;
+ new->FaultHandler = cur->FaultHandler;
for( i = 0; i < NUM_CFG_ENTRIES; i ++ )
{
RELEASE( &giThreadListLock );
}
-#if 0
/**
- * \fn void Threads_SetSignalHandler(int Num, void *Handler)
+ * \fn void Threads_SetSignalHandler(Uint Handler)
* \brief Sets the signal handler for a signal
*/
-void Threads_SetSignalHandler(int Num, void *Handler)
-{
- if(Num < 0 || Num >= NSIG) return;
-
- gCurrentThread->SignalHandlers[Num] = Handler;
+void Threads_SetFaultHandler(Uint Handler)
+{
+ Log_Log("Threads", "Threads_SetFaultHandler: Handler = %p", Handler);
+ Proc_GetCurThread()->FaultHandler = Handler;
}
/**
- * \fn void Threads_SendSignal(int TID, int Num)
- * \brief Send a signal to a thread
+ * \fn void Threads_Fault(int Num)
+ * \brief Calls a fault handler
*/
-void Threads_SendSignal(int TID, int Num)
+void Threads_Fault(int Num)
{
- tThread *thread = Proc_GetThread(TID);
- void *handler;
+ tThread *thread = Proc_GetCurThread();
+
+ Log_Log("Threads", "Threads_Fault: thread = %p", thread);
if(!thread) return ;
- handler = thread->SignalHandlers[Num];
+ Log_Log("Threads", "Threads_Fault: thread->FaultHandler = %p", thread->FaultHandler);
- // Panic?
- if(handler == SIG_ERR) {
- Proc_Kill(TID);
+ switch(thread->FaultHandler)
+ {
+ case 0: // Panic?
+ Threads_Kill(thread, -1);
+ HALT();
return ;
- }
- // Dump Core?
- if(handler == -2) {
- Proc_Kill(TID);
+ case 1: // Dump Core?
+ Threads_Kill(thread, -1);
+ HALT();
return ;
}
- // Ignore?
- if(handler == -2) return;
-
- // Check the type and handle if the thread is already in a signal
- if(thread->CurSignal != 0) {
- if(Num < _SIGTYPE_FATAL)
- Proc_Kill(TID);
- } else {
- while(thread->CurSignal != 0)
- Proc_Yield();
- }
+
+ // Double Fault? Oh, F**k
+ if(thread->CurFaultNum != 0) {
+ Threads_Kill(thread, -1); // For now, just kill
+ HALT();
}
- //TODO:
+ Proc_CallFaultHandler(thread);
}
-#endif
// --- Process Structure Access Functions ---
tPID Threads_GetPID()
*/
void Threads_SegFault(tVAddr Addr)
{
- //Threads_SendSignal( Proc_GetCurThread()->TID, SIGSEGV );
Warning("Thread #%i committed a segfault at address %p", Proc_GetCurThread()->TID, Addr);
- Threads_Exit( 0, -1 );
+ Threads_Fault( 1 );
+ //Threads_Exit( 0, -1 );
}
// === EXPORTS ===
// Call Interrupt\r
VM8086_Int(gpVesa_BiosState, 0x10);\r
if(gpVesa_BiosState->AX != 0x004F) {\r
- Log_Warning("VESA", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)\n", gpVesa_BiosState->AX);\r
+ Log_Warning("VESA", "Vesa_Install - VESA/VBE Unsupported (AX = 0x%x)", gpVesa_BiosState->AX);\r
return MODULE_ERR_NOTNEEDED;\r
}\r
\r
{\r
tVT_Char *chars = Buffer;\r
int pitch = gVesa_Modes[giVesaCurrentMode].width;\r
- int widthInChars;\r
+ int widthInChars = gVesa_Modes[giVesaCurrentMode].width/giVT_CharWidth;\r
+ int heightInChars = gVesa_Modes[giVesaCurrentMode].height/giVT_CharHeight;\r
int x, y;\r
Uint32 *dest = (void*)gpVesa_Framebuffer;\r
int i;\r
Offset /= sizeof(tVT_Char);\r
\r
LOG("gVesa_Modes[%i].width = %i", giVesaCurrentMode, gVesa_Modes[giVesaCurrentMode].width);\r
- widthInChars = gVesa_Modes[giVesaCurrentMode].width/giVT_CharWidth;\r
x = Offset % widthInChars;\r
y = Offset / widthInChars;\r
LOG("(x,y) = (%i,%i) = [%i,%i]", x, y, x * giVT_CharWidth, y * giVT_CharHeight * pitch);\r
);\r
\r
// Sanity Check\r
- if(y > gVesa_Modes[giVesaCurrentMode].height/giVT_CharHeight) {\r
+ if(y > heightInChars) {\r
LEAVE('i', 0);\r
return 0;\r
}\r
\r
+ if( Offset + Length > heightInChars*widthInChars ) {\r
+ Length = heightInChars*widthInChars - Offset;\r
+ Log_Notice("VESA", "Clipping write size to %i characters", (int)Length);\r
+ }\r
+ \r
dest += y * giVT_CharHeight * pitch;\r
dest += x * giVT_CharWidth;\r
\r
VT_Colour12to24(chars->FGCol)\r
);\r
\r
- \r
chars ++;\r
x ++;\r
if( x >= widthInChars ) {\r
int Vesa_Ioctl(tVFS_Node *Node, int ID, void *Data)\r
{\r
int ret;\r
+ //Log_Debug("VESA", "Vesa_Ioctl: (Node=%p, ID=%i, Data=%p)", Node, ID, Data);\r
switch(ID)\r
{\r
case DRV_IOCTL_TYPE: return DRV_TYPE_VIDEO;\r
}\r
return ret;\r
\r
+ case VIDEO_IOCTL_SETCURSOR: // Set cursor position\r
+ return 0;\r
+ \r
case VIDEO_IOCTL_REQLFB: // Request Linear Framebuffer\r
return 0;\r
}\r
SYSCALL1 _exit, SYS_EXIT
SYSCALL2 clone, SYS_CLONE
SYSCALL2 kill, SYS_KILL
-SYSCALL2 signal, SYS_SIGNAL
SYSCALL0 yield, SYS_YIELD
SYSCALL0 sleep, SYS_SLEEP
SYSCALL1 wait, SYS_WAIT
SYSCALL3 execve, SYS_EXECVE
SYSCALL2 SysLoadBin, SYS_LOADBIN
+SYSCALL1 _SysSetFaultHandler, SYS_SETFAULTHANDLER
SYSCALL6 _SysDebug, 0x100
*/\r
#include "stdio_int.h"\r
#include "lib.h"\r
+#include <stdio.h>\r
+#include <sys/sys.h>\r
\r
#define USE_CPUID 0\r
\r
#if USE_CPUID\r
static void cpuid(uint32_t Num, uint32_t *EAX, uint32_t *EBX, uint32_t *EDX, uint32_t *ECX);\r
#endif\r
+void ErrorHandler(int Fault);\r
\r
// === GLOBALS ===\r
extern char **_envp;\r
}\r
#endif\r
\r
+ _SysSetFaultHandler(ErrorHandler);\r
+ \r
return 1;\r
}\r
\r
+void ErrorHandler(int Fault)\r
+{\r
+ fprintf(stderr, "Fault = %i\n", Fault);\r
+}\r
\r
#if USE_CPUID\r
/**\r
extern int sendmsg(int dest, unsigned int *Data);\r
extern int pollmsg(int *src, unsigned int *Data);\r
extern int getmsg(int *src, unsigned int *Data);\r
+\r
+extern int _SysSetFaultHandler(void (*Handler)(int));\r