From 950126c76c539e76574f6349b833f41c70ed6573 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 16 Feb 2013 17:11:49 +0800 Subject: [PATCH] Kernel - Signals partially implimented - No userland bindings, or kernel actions yet --- KernelLand/Kernel/arch/x86/desctab.asm | 21 +---- KernelLand/Kernel/arch/x86/proc.asm | 120 ++++++++++++++---------- KernelLand/Kernel/arch/x86/proc.c | 30 ++++++ KernelLand/Kernel/include/signal.h | 28 +++++- KernelLand/Kernel/include/threads_int.h | 7 ++ KernelLand/Kernel/threads.c | 60 ++++++++++++ 6 files changed, 194 insertions(+), 72 deletions(-) diff --git a/KernelLand/Kernel/arch/x86/desctab.asm b/KernelLand/Kernel/arch/x86/desctab.asm index 18ed10d3..354a001e 100644 --- a/KernelLand/Kernel/arch/x86/desctab.asm +++ b/KernelLand/Kernel/arch/x86/desctab.asm @@ -220,13 +220,12 @@ Isr240.jmp: %assign i i+1 %endrep +[extern ReturnFromInterrupt] ; --------------------- ; Common error handling ; --------------------- [extern ErrorHandler] ErrorCommon: - ;xchg bx, bx ; MAGIC BREAK - pusha push ds push es @@ -248,13 +247,7 @@ ErrorCommon: call ErrorHandler add esp, 4 - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 ; Error Code and ID - iret + jmp ReturnFromInterrupt ; -------------------------- ; Common System Call Handler @@ -282,14 +275,8 @@ SyscallCommon: and eax, 0x100 ; 0x100 = Trace Flag and WORD [esp+(4+8+2+2)*4], ~0x100 ; Clear or DWORD [esp+(4+8+2+2)*4], eax ; Set for user - - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 ; Error Code and ID - iret + + jmp ReturnFromInterrupt ; ------------ ; IRQ Handling diff --git a/KernelLand/Kernel/arch/x86/proc.asm b/KernelLand/Kernel/arch/x86/proc.asm index 8da79711..dcafc5f1 100644 --- a/KernelLand/Kernel/arch/x86/proc.asm +++ b/KernelLand/Kernel/arch/x86/proc.asm @@ -215,9 +215,9 @@ scheduler_return: ; Used by some hackery in Proc_DumpThreadCPUState mov al, 0x20 out 0x20, al ; ACK IRQ + %if USE_MP jmp .ret - .sendEOI: mov eax, DWORD [gpMP_LocalAPIC] mov DWORD [eax+0x0B0], 0 @@ -225,15 +225,60 @@ scheduler_return: ; Used by some hackery in Proc_DumpThreadCPUState .ret: pop eax ; Debug Register 0, Current Thread mov dr0, eax + + jmp ReturnFromInterrupt +; +; Returns after an interrupt, restoring the user state +; - Also handles signal handlers +; +[global ReturnFromInterrupt] +[extern Threads_GetPendingSignal] +[extern Threads_GetSignalHandler] +[extern Proc_CallUser] +ReturnFromInterrupt: + ; Check that we're returning to userland + test DWORD [esp+(4+8+2+1)*4], 0x07 + jz .ret ; Kernel interrupted, return + + call Threads_GetPendingSignal + ; eax: signal number + test eax, eax + jz .ret + + ; There's a signal pending, funtime + push eax + call Threads_GetSignalHandler + ; eax: signal handler + pop ecx + test eax, eax + jz .ret + cmp eax, -1 + jz .default + + ; (some stack abuse) + push User_RestoreState + push ecx + mov ecx, esp + + push (2+4+8+2+2)*4 ; Up to and incl. CS + push ecx ; User stack data base + push DWORD [ecx+(2+4+8+2+3)*4] ; User SP + push eax ; handler + call Proc_CallUser + ; Oh, ... it failed. Default time? + add esp, (4+2)*4 +.default: + + + ; Fall through to return +.ret: pop gs pop fs pop es pop ds - popa - add esp, 4*2 ; CPU ID + Dummy error code - ; No Error code / int num + add esp, 2*4 ; IRQ Num / CPU ID + error code iret [extern Proc_Clone] @@ -286,52 +331,17 @@ Proc_ReturnToUser: ; Good thing this can only be called on a user fault. ; - ; Validate user ESP - ; - Page Table - mov edx, [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4 - mov ecx, edx - shr ecx, 22 - test BYTE [0xFC3F0000+ecx*4], 1 - jnz .justKillIt - ; - Page - mov ecx, edx - shr ecx, 12 - test BYTE [0xFC000000+ecx*4], 1 - jnz .justKillIt - ; Adjust - sub edx, 8 - ; - Page Table - mov ecx, edx - shr ecx, 22 - test BYTE [0xFC3F0000+ecx*4], 1 - jnz .justKillIt - ; - Page - mov ecx, edx - shr ecx, 12 - test BYTE [0xFC000000+ecx*4], 1 - jnz .justKillIt - - ; Get and alter User SP - mov edi, edx - mov edx, [ebp+12] ; Get parameter - mov [edi+4], edx ; save to user stack - mov [edi], DWORD User_Syscall_RetAndExit ; Return Address - - ; Restore Segment Registers - mov ax, 0x23 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - push 0x23 ; SS - push edi ; ESP - push 0x202 ; EFLAGS (IP and Rsvd) - push 0x1B ; CS - mov eax, [ebp+8] ; Method to call - push eax ; EIP - - iret + ; Create data to add to user stack + push DWORD [ebp+12] + push User_Syscall_RetAndExit + mov ecx, esp + + ; Call user method + push 2*4 + push ecx + push DWORD [eax+KSTACK_USERSTATE_SIZE-12] ; User ESP is at top of kstack - 3*4 + push DWORD [ebp+8] + call Proc_CallUser ; Just kill the bleeding thing ; (I know it calls int 0xAC in kernel mode, but meh) @@ -363,6 +373,16 @@ User_Syscall: xchg bx, bx ; MAGIC BREAKPOINT int 0xAC +User_RestoreState: + pop gs + pop fs + pop es + pop ds + popa + add esp, 2*4 ; Kernel's error code and interrupt number + retf ; EFLAGS/SS/ESP were not included in the state + + ; A place to return to and exit User_Syscall_RetAndExit: push eax diff --git a/KernelLand/Kernel/arch/x86/proc.c b/KernelLand/Kernel/arch/x86/proc.c index 8b05488b..4847d510 100644 --- a/KernelLand/Kernel/arch/x86/proc.c +++ b/KernelLand/Kernel/arch/x86/proc.c @@ -50,6 +50,7 @@ extern char scheduler_return[]; // Return address in SchedulerBase extern char IRQCommon[]; // Common IRQ handler code extern char IRQCommon_handled[]; // IRQCommon call return location extern char GetEIP_Sched_ret[]; // GetEIP call return location +extern void Timer_CallTimers(void); // === PROTOTYPES === //void ArchThreads_Init(void); @@ -67,6 +68,7 @@ void Proc_ChangeStack(void); Uint Proc_MakeUserStack(void); //void Proc_StartUser(Uint Entrypoint, Uint *Bases, int ArgC, char **ArgV, char **EnvP, int DataSize); void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) NORETURN; +void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen); //void Proc_CallFaultHandler(tThread *Thread); //void Proc_DumpThreadCPUState(tThread *Thread); void Proc_Scheduler(int CPU); @@ -633,6 +635,34 @@ void Proc_StartProcess(Uint16 SS, Uint Stack, Uint Flags, Uint16 CS, Uint IP) for(;;); } +void Proc_CallUser(Uint32 UserIP, Uint32 UserSP, const void *StackData, size_t StackDataLen) +{ + if( UserSP < StackDataLen ) + return ; + if( !CheckMem( (void*)(UserSP - StackDataLen), StackDataLen ) ) + return ; + memcpy( (void*)(UserSP - StackDataLen), StackData, StackDataLen ); + + __asm__ __volatile__ ( + "mov $0x23,%%ax;\n\t" + "mov %%ax, %%ds;\n\t" + "mov %%ax, %%es;\n\t" + "mov %%ax, %%fs;\n\t" + "mov %%ax, %%gs;\n\t" + "push $0x23;\n\t" + "push %1;\n\t" + "push $0x202;\n\t" + "push $0x1B;\n\t" + "push %0;\n\t" + "iret;\n\t" + : + : "r" (UserIP), "r" (UserSP - StackDataLen) + : "eax" + ); + for(;;) + ; +} + /** * \brief Calls a signal handler in user mode * \note Used for signals diff --git a/KernelLand/Kernel/include/signal.h b/KernelLand/Kernel/include/signal.h index d97d6dcb..3f2a9c4f 100644 --- a/KernelLand/Kernel/include/signal.h +++ b/KernelLand/Kernel/include/signal.h @@ -5,12 +5,30 @@ #ifndef _SIGNAL_H_ #define _SIGNAL_H_ +#define SIG_DFL NULL + enum eSignals { - SIGKILL, - SIGSTOP, - SIGCONT, - SIGCHLD, - NSIG + SIGNONE = 0, // No signal + SIGHUP = 1, + SIGINT = 2, // C + SIGQUIT = 3, // POSIX + SIGILL = 4, // C + SIGTRAP = 5, // POSIX + SIGABRT = 6, // C? + SIGBUS = 7, // ? + SIGFPE = 8, // C + SIGKILL = 9, // POSIX + SIGUSR1 = 10, + SIGSEGV = 11, // C + SIGUSR2 = 12, + SIGPIPE = 13, // + SIGALRM = 14, + SIGTERM = 15, + _SIG16 = 16, + SIGCHLD = 17, + SIGCONT = 18, + SIGSTOP = 19, + NSIGNALS }; #endif diff --git a/KernelLand/Kernel/include/threads_int.h b/KernelLand/Kernel/include/threads_int.h index 09e58c16..d7706680 100644 --- a/KernelLand/Kernel/include/threads_int.h +++ b/KernelLand/Kernel/include/threads_int.h @@ -12,6 +12,7 @@ #include #include #include +#include typedef struct sProcess tProcess; @@ -45,6 +46,8 @@ struct sProcess int MaxFD; char *CurrentWorkingDir; char *RootDir; + + void *SignalHandlers[NSIGNALS]; }; /** @@ -86,6 +89,10 @@ struct sThread int CurFaultNum; //!< Current fault number, 0: none tVAddr FaultHandler; //!< Fault Handler + + int PendingSignal; //!< Pending signal ID (0 = none) + + tMsg * volatile Messages; //!< Message Queue tMsg *LastMessage; //!< Last Message (speeds up insertion) diff --git a/KernelLand/Kernel/threads.c b/KernelLand/Kernel/threads.c index 7dd9f6e9..007d16ff 100644 --- a/KernelLand/Kernel/threads.c +++ b/KernelLand/Kernel/threads.c @@ -66,6 +66,10 @@ tThread *Threads_RemActive(void); void Threads_ToggleTrace(int TID); void Threads_Fault(int Num); void Threads_SegFault(tVAddr Addr); +void Threads_PostSignal(int SignalNum); + int Threads_GetPendingSignal(void); +void Threads_SetSignalHandler(int SignalNum, void *Handler); +void *Threads_GetSignalHandler(int SignalNum); #if 0 int Threads_GetPID(void); int Threads_GetTID(void); @@ -1004,6 +1008,62 @@ void Threads_SegFault(tVAddr Addr) //Threads_Exit( 0, -1 ); } + +void Threads_PostSignal(int SignalNum) +{ + tThread *cur = Proc_GetCurThread(); + cur->PendingSignal = SignalNum; + Threads_PostEvent(cur, THREAD_EVENT_SIGNAL); +} + +/** + */ +int Threads_GetPendingSignal(void) +{ + tThread *cur = Proc_GetCurThread(); + + // Atomic AND with 0 fetches and clears in one operation + return __sync_fetch_and_and( &cur->PendingSignal, 0 ); +} + +/* + * \brief Update the current thread's signal handler + */ +void Threads_SetSignalHandler(int SignalNum, void *Handler) +{ + if( SignalNum <= 0 || SignalNum >= NSIGNALS ) + return ; + if( !MM_IsUser(Handler) ) + return ; + Proc_GetCurThread()->Process->SignalHandlers[SignalNum] = Handler; +} + +/** + * \return 0 Ignore + */ +void *Threads_GetSignalHandler(int SignalNum) +{ + if( SignalNum <= 0 || SignalNum >= NSIGNALS ) + return NULL; + void *ret = Proc_GetCurThread()->Process->SignalHandlers[SignalNum]; + if( !ret ) + { + // Defaults + switch(SignalNum) + { + case SIGINT: + case SIGKILL: + case SIGSEGV: +// ret = User_Signal_Kill; + break; + default: + ret = NULL; + break; + } + } + return ret; +} + // --- Process Structure Access Functions --- tPGID Threads_GetPGID(void) { -- 2.20.1