%assign i i+1
%endrep
+[extern ReturnFromInterrupt]
; ---------------------
; Common error handling
; ---------------------
[extern ErrorHandler]
ErrorCommon:
- ;xchg bx, bx ; MAGIC BREAK
-
pusha
push ds
push es
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
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
mov al, 0x20
out 0x20, al ; ACK IRQ
+
%if USE_MP
jmp .ret
-
.sendEOI:
mov eax, DWORD [gpMP_LocalAPIC]
mov DWORD [eax+0x0B0], 0
.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]
; 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)
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
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);
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);
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
#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
#include <threads.h>
#include <proc.h>
#include <timers_int.h>
+#include <signal.h>
typedef struct sProcess tProcess;
int MaxFD;
char *CurrentWorkingDir;
char *RootDir;
+
+ void *SignalHandlers[NSIGNALS];
};
/**
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)
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);
//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)
{