diff --git a/hal/armv7a/_interrupts.S b/hal/armv7a/_interrupts.S index 252b42bd4..e8c67acb9 100644 --- a/hal/armv7a/_interrupts.S +++ b/hal/armv7a/_interrupts.S @@ -293,3 +293,38 @@ _syscalls_dispatch: add sp, sp, #8 b _hal_cpuRestoreCtx .size _syscalls_dispatch, .-_syscalls_dispatch + + +.globl hal_excjmp +.type hal_excjmp, %function +hal_excjmp: + ldr r1, [r0], #4 + msr cpsr_fsxc, r1 + ldr sp, [r0], #4 + ldr lr, [r0], #4 + ldm r0, {r4-r11} + + mov r0, #1 + bx lr +.size hal_excjmp, .-hal_excjmp + + +/* int hal_setexcjmp(excjmp_context_t *ctx, excjmp_context_t **oldctx) */ +.globl hal_setexcjmp +.type hal_setexcjmp, %function +hal_setexcjmp: + mrs r2, cpsr + str r2, [r0], #4 + str sp, [r0], #4 + str lr, [r0], #4 + stm r0, {r4-r11} + + mov r4, lr + sub r0, #12 + bl threads_setexcjmp + + mov lr, r4 + + mov r0, #0 + bx lr +.size hal_setexcjmp, .-hal_setexcjmp diff --git a/hal/armv7a/arch/exceptions.h b/hal/armv7a/arch/exceptions.h index 35ddcf704..97ae3e16a 100644 --- a/hal/armv7a/arch/exceptions.h +++ b/hal/armv7a/arch/exceptions.h @@ -35,4 +35,19 @@ typedef struct _exc_context_t { cpu_context_t cpuCtx; } exc_context_t; + +typedef struct _excjmp_context_t { + u32 cpsr; + u32 sp; + u32 ret; + u32 r4; + u32 r5; + u32 r6; + u32 r7; + u32 r8; + u32 r9; + u32 r10; + u32 r11; +} excjmp_context_t; + #endif diff --git a/hal/armv7a/cpu.c b/hal/armv7a/cpu.c index 113e63bb4..3f8f21193 100644 --- a/hal/armv7a/cpu.c +++ b/hal/armv7a/cpu.c @@ -17,6 +17,8 @@ #include "hal/string.h" #include "hal/spinlock.h" #include "hal/hal.h" +#include "arch/exceptions.h" +#include "include/errno.h" #include "armv7a.h" #include "config.h" @@ -96,8 +98,12 @@ int hal_cpuCreateContext(cpu_context_t **nctx, void *start, void *kstack, size_t } +extern void threads_setexcjmp(excjmp_context_t *ctx, excjmp_context_t **oldctx); + + int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { + excjmp_context_t excctx, *oldctx; cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { { &ctx->psr, sizeof(ctx->psr) }, @@ -110,19 +116,26 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal (void)src; - hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); + if (!hal_setexcjmp(&excctx, &oldctx)) { + hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); - signalCtx->pc = (u32)handler & ~1; - signalCtx->sp -= sizeof(cpu_context_t); + signalCtx->pc = (u32)handler & ~1; + signalCtx->sp -= sizeof(cpu_context_t); - if (((u32)handler & 1) != 0) { - signalCtx->psr |= THUMB_STATE; + if (((u32)handler & 1) != 0) { + signalCtx->psr |= THUMB_STATE; + } + else { + signalCtx->psr &= ~THUMB_STATE; + } + + hal_stackPutArgs((void **)&signalCtx->sp, sizeof(args) / sizeof(args[0]), args); } else { - signalCtx->psr &= ~THUMB_STATE; + threads_setexcjmp(oldctx, NULL); + return -EFAULT; } - - hal_stackPutArgs((void **)&signalCtx->sp, sizeof(args) / sizeof(args[0]), args); + threads_setexcjmp(oldctx, NULL); return 0; } diff --git a/hal/armv7a/exceptions.c b/hal/armv7a/exceptions.c index f5d5748c5..13cffbb48 100644 --- a/hal/armv7a/exceptions.c +++ b/hal/armv7a/exceptions.c @@ -119,8 +119,19 @@ static void exceptions_defaultHandler(unsigned int n, exc_context_t *ctx) extern void threads_setupUserReturn(void *retval, cpu_context_t *ctx); +extern excjmp_context_t *threads_getexcjmp(void); + + +extern void hal_excjmp(excjmp_context_t *ctx); + + void exceptions_dispatch(unsigned int n, exc_context_t *ctx) { + excjmp_context_t *excctx = threads_getexcjmp(); + if (excctx != NULL) { + hal_excjmp(excctx); + } + if (n == exc_prefetch || n == exc_abort) exceptions.abortHandler(n, ctx); else if (n == exc_undef) diff --git a/hal/cpu.h b/hal/cpu.h index cde1b94a9..a210f36b9 100644 --- a/hal/cpu.h +++ b/hal/cpu.h @@ -20,6 +20,7 @@ #define SIG_SRC_SCALL 1 #include +#include #include "spinlock.h" @@ -113,6 +114,9 @@ extern void hal_cpuSigreturn(void *kstack, void *ustack, cpu_context_t **ctx); extern void hal_jmp(void *f, void *kstack, void *ustack, size_t kargc, const arg_t *kargs); +extern int hal_setexcjmp(excjmp_context_t *ctx, excjmp_context_t **oldctx); + + /* core management */ diff --git a/hal/ia32/_exceptions.S b/hal/ia32/_exceptions.S index 23a82202c..4595d3c27 100644 --- a/hal/ia32/_exceptions.S +++ b/hal/ia32/_exceptions.S @@ -112,6 +112,62 @@ exception_popContext: iret .size exception_popContext, .-exception_popContext + +/* int hal_setexcjmp(cpu_context_t *ctx, cpu_context_t **oldctx) */ +.globl hal_setexcjmp +.type hal_setexcjmp, %function +hal_setexcjmp: + pushfl + popl %ecx + + movl 4(%esp), %eax /* eax := ctx */ + + movl %ecx, 160(%eax) + + leal 4(%eax), %ecx + movl %ecx, (%eax) + /* Save calee-saved registers */ + movl %edi, 4(%eax) + movl %esi, 8(%eax) + movl %ebp, 12(%eax) + movl %ebx, 24(%eax) + + movw %gs, 32(%eax) + movw %fs, 34(%eax) + movw %es, 36(%eax) + movw %ds, 38(%eax) + movw %cs, 156(%eax) + movw $0, 158(%eax) + movw %ss, 168(%eax) + movw $0, 170(%eax) + + movl %cr0, %ecx + movl %ecx, 148(%eax) + + movl %esp, 16(%eax) /* ctx.edx := esp to revert (popContext to supervisor mode does not change esp) */ + /* save ctx.PC as label 1: */ + leal (1f), %ecx + movl %ecx, 152(%eax) + + movl (%esp), %ecx /* ecx := return address */ + movl %ecx, 20(%eax) /* ctx.ecx := return address */ + + pushl 8(%esp) /* oldctx */ + pushl 8(%esp) /* ctx */ + call threads_setexcjmp + popl %eax + popl %eax + + movl $0, %eax + ret +1: + movl %edx, %esp + movl %ecx, (%esp) /* restore return address */ + movl $1, %eax + ret +.size hal_setexcjmp, .-hal_setexcjmp + + /* Used for FPU lazy context stacking */ .globl exceptions_exc7_handler .align 4, 0x90 @@ -142,6 +198,13 @@ sym: /* Exception handling macro */ #define EXCSTUB(exc)\ call exception_pushContext;\ + ;\ + call threads_getexcjmp;\ + testl %eax, %eax;\ + jz 1f;\ + leal -28(%eax), %esp;\ + jmp exception_popContext;\ +1:\ movl $SEL_KDATA, %eax;\ movw %ax, %ds;\ movw %ax, %es;\ diff --git a/hal/ia32/arch/exceptions.h b/hal/ia32/arch/exceptions.h index c4d9ee680..40c90da4a 100644 --- a/hal/ia32/arch/exceptions.h +++ b/hal/ia32/arch/exceptions.h @@ -40,6 +40,8 @@ typedef struct { cpu_context_t cpuCtx; } exc_context_t; +typedef cpu_context_t excjmp_context_t; + #pragma pack(pop) #endif diff --git a/hal/ia32/cpu.c b/hal/ia32/cpu.c index 93915f3bf..06650a51b 100644 --- a/hal/ia32/cpu.c +++ b/hal/ia32/cpu.c @@ -26,6 +26,7 @@ #include "ia32.h" #include "halsyspage.h" #include "init.h" +#include "proc/threads.h" #include @@ -179,6 +180,7 @@ void _hal_cpuSetKernelStack(void *kstack) int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signalCtx, int n, unsigned int oldmask, const int src) { + cpu_context_t excctx, *oldctx; cpu_context_t *ctx = (void *)((char *)kstack - sizeof(cpu_context_t)); const struct stackArg args[] = { { &ctx->esp, sizeof(ctx->esp) }, @@ -190,12 +192,20 @@ int hal_cpuPushSignal(void *kstack, void (*handler)(void), cpu_context_t *signal (void)src; - hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); - signalCtx->eip = (u32)handler; - signalCtx->esp -= sizeof(cpu_context_t); + if (!hal_setexcjmp(&excctx, &oldctx)) { + hal_memcpy(signalCtx, ctx, sizeof(cpu_context_t)); - hal_stackPutArgs((void **)&signalCtx->esp, sizeof(args) / sizeof(args[0]), args); + signalCtx->eip = (u32)handler; + signalCtx->esp -= sizeof(cpu_context_t); + + hal_stackPutArgs((void **)&signalCtx->esp, sizeof(args) / sizeof(args[0]), args); + } + else { + threads_setexcjmp(oldctx, NULL); + return -EFAULT; + } + threads_setexcjmp(oldctx, NULL); return 0; } diff --git a/proc/threads.c b/proc/threads.c index 6d3be0161..ca4cd9718 100644 --- a/proc/threads.c +++ b/proc/threads.c @@ -21,6 +21,7 @@ #include "lib/lib.h" #include "posix/posix.h" #include "log/log.h" +#include "process.h" #include "resource.h" #include "msg.h" #include "ports.h" @@ -35,11 +36,15 @@ struct { vm_map_t *kmap; spinlock_t spinlock; lock_t lock; + + /* Synchronized by spinlock */ thread_t *ready[8]; + /* + * Write to current[i] only by i'th cpu, with spinlock set. + * Read from current[i] by i'th cpu allowed without spinlock. + */ thread_t **current; time_t utcoffs; - - /* Synchronized by spinlock */ rbtree_t sleeping; /* Synchronized by mutex */ @@ -66,7 +71,6 @@ struct { } threads_common; -static thread_t *_proc_current(void); static void _proc_threadDequeue(thread_t *t); static int _proc_threadWait(thread_t **queue, time_t timeout, spinlock_ctx_t *scp); @@ -224,7 +228,7 @@ void perf_fork(process_t *p) ev.type = perf_levFork; ev.pid = perf_idpack(process_getPid(p)); // ev.ppid = p->parent != NULL ? perf_idpack(p->parent->id) : -1; - ev.tid = perf_idpack(proc_getTid(_proc_current())); + ev.tid = perf_idpack(proc_getTid(proc_current())); now = _proc_gettimeRaw(); ev.deltaTimestamp = now - threads_common.perfLastTimestamp; @@ -248,7 +252,7 @@ void perf_kill(process_t *p) ev.sbz = 0; ev.type = perf_levKill; ev.pid = perf_idpack(process_getPid(p)); - ev.tid = perf_idpack(proc_getTid(_proc_current())); + ev.tid = perf_idpack(proc_getTid(proc_current())); now = _proc_gettimeRaw(); ev.deltaTimestamp = now - threads_common.perfLastTimestamp; @@ -272,7 +276,7 @@ void perf_exec(process_t *p, char *path) hal_spinlockSet(&threads_common.spinlock, &sc); ev.sbz = 0; ev.type = perf_levExec; - ev.tid = perf_idpack(proc_getTid(_proc_current())); + ev.tid = perf_idpack(proc_getTid(proc_current())); plen = hal_strlen(path); plen = min(plen, sizeof(ev.path) - 1); @@ -547,7 +551,7 @@ __attribute__((noreturn)) void proc_longjmp(cpu_context_t *ctx) thread_t *current; hal_spinlockSet(&threads_common.spinlock, &sc); - current = _proc_current(); + current = proc_current(); current->longjmpctx = ctx; hal_cpuReschedule(&threads_common.spinlock, &sc); for (;;) { @@ -555,6 +559,23 @@ __attribute__((noreturn)) void proc_longjmp(cpu_context_t *ctx) } +void threads_setexcjmp(excjmp_context_t *ctx, excjmp_context_t **oldctx) +{ + thread_t *current = proc_current(); + + if (oldctx != NULL) { + *oldctx = current->excjmpctx; + } + current->excjmpctx = ctx; +} + + +excjmp_context_t *threads_getexcjmp(void) +{ + return proc_current()->excjmpctx; +} + + static int _threads_checkSignal(thread_t *selected, process_t *proc, cpu_context_t *signalCtx, unsigned int oldmask, const int src); @@ -569,7 +590,7 @@ int _threads_schedule(unsigned int n, cpu_context_t *context, void *arg) (void)n; hal_lockScheduler(); - current = _proc_current(); + current = proc_current(); threads_common.current[hal_cpuGetID()] = NULL; /* Save current thread context */ @@ -675,26 +696,9 @@ int threads_schedule(unsigned int n, cpu_context_t *context, void *arg) } -static thread_t *_proc_current(void) -{ - thread_t *current; - - current = threads_common.current[hal_cpuGetID()]; - - return current; -} - - thread_t *proc_current(void) { - thread_t *current; - spinlock_ctx_t sc; - - hal_spinlockSet(&threads_common.spinlock, &sc); - current = _proc_current(); - hal_spinlockClear(&threads_common.spinlock, &sc); - - return current; + return threads_common.current[hal_cpuGetID()]; } @@ -780,6 +784,7 @@ int proc_threadCreate(process_t *process, void (*start)(void *), int *id, unsign proc_gettime(&t->startTime, NULL); t->lastTime = t->startTime; t->longjmpctx = NULL; + t->excjmpctx = NULL; if (thread_alloc(t) < 0) { vm_kfree(t->kstack); @@ -925,7 +930,7 @@ int proc_threadPriority(int priority) hal_spinlockSet(&threads_common.spinlock, &sc); - current = _proc_current(); + current = proc_current(); /* NOTE: -1 is used to retrieve the current thread priority only */ if (priority >= 0) { @@ -1097,7 +1102,7 @@ static void _proc_threadEnqueue(thread_t **queue, time_t timeout, int interrupti return; } - current = _proc_current(); + current = proc_current(); LIST_ADD(queue, current); @@ -1145,7 +1150,7 @@ int proc_threadSleep(time_t us) if (us != 0) { now = _proc_gettimeRaw(); - current = _proc_current(); + current = proc_current(); current->state = SLEEP; current->wait = NULL; current->wakeup = now + us; @@ -1293,7 +1298,7 @@ int proc_join(int tid, time_t timeout) hal_spinlockSet(&threads_common.spinlock, &sc); now = _proc_gettimeRaw(); - current = _proc_current(); + current = proc_current(); if (proc_getTid(current) == tid) { hal_spinlockClear(&threads_common.spinlock, &sc); return -EDEADLK; @@ -1483,16 +1488,19 @@ static int _threads_checkSignal(thread_t *selected, process_t *proc, cpu_context #ifndef KERNEL_SIGNALS_DISABLE unsigned int sig; + int ret; sig = (selected->sigpend | proc->sigpend) & ~selected->sigmask; if ((sig != 0) && (proc->sighandler != NULL)) { sig = hal_cpuGetLastBit(sig); - if (hal_cpuPushSignal(selected->kstack + selected->kstacksz, proc->sighandler, signalCtx, sig, oldmask, src) == 0) { + ret = hal_cpuPushSignal(selected->kstack + selected->kstacksz, proc->sighandler, signalCtx, sig, oldmask, src); + if (ret == 0) { selected->sigpend &= ~(1 << sig); proc->sigpend &= ~(1 << sig); return 0; } + return ret; } #endif @@ -1508,20 +1516,32 @@ void threads_setupUserReturn(void *retval, cpu_context_t *ctx) void *f; void *kstackTop; thread_t *thread; + int ret; hal_spinlockSet(&threads_common.spinlock, &sc); - thread = _proc_current(); + thread = proc_current(); kstackTop = thread->kstack + thread->kstacksz; signalCtx = (void *)((char *)hal_cpuGetUserSP(ctx) - sizeof(*signalCtx)); hal_cpuSetReturnValue(ctx, retval); - if (_threads_checkSignal(thread, thread->process, signalCtx, thread->sigmask, SIG_SRC_SCALL) == 0) { + ret = _threads_checkSignal(thread, thread->process, signalCtx, thread->sigmask, SIG_SRC_SCALL); + if (ret == 0) { f = thread->process->sighandler; hal_spinlockClear(&threads_common.spinlock, &sc); hal_jmp(f, kstackTop, hal_cpuGetUserSP(signalCtx), 0, NULL); /* no return */ } + else if (ret == -EFAULT) { +#ifndef NDEBUG + hal_consolePrint(ATTR_BOLD, "EFAULT in _threads_checkSignal, killing whole process\n"); +#endif + hal_spinlockClear(&threads_common.spinlock, &sc); + proc_kill(thread->process); + thread->exit = THREAD_END_NOW; + hal_cpuReschedule(NULL, NULL); + return; + } hal_spinlockClear(&threads_common.spinlock, &sc); } @@ -1538,7 +1558,7 @@ int threads_sigsuspend(unsigned int mask) /* changing sigmask and sleep shall be atomic - do it under lock (sigpost is done also under threads_common.spinlock) */ hal_spinlockSet(&threads_common.spinlock, &sc); - thread = _proc_current(); + thread = proc_current(); /* setup syscall return value - sigsuspend always returns -EINTR */ kstackTop = thread->kstack + thread->kstacksz; @@ -1615,7 +1635,7 @@ int proc_lockTry(lock_t *lock) hal_spinlockSet(&lock->spinlock, &lsc); hal_spinlockSet(&threads_common.spinlock, &tcsc); - current = _proc_current(); + current = proc_current(); err = _proc_lockTry(current, lock); @@ -1634,7 +1654,7 @@ static int _proc_lockSet(lock_t *lock, int interruptible, spinlock_ctx_t *scp) hal_spinlockSet(&threads_common.spinlock, &sc); - current = _proc_current(); + current = proc_current(); if ((lock->attr.type == PH_LOCK_ERRORCHECK) && (lock->owner == current)) { hal_spinlockClear(&threads_common.spinlock, &sc); @@ -1743,7 +1763,7 @@ static int _proc_lockUnlock(lock_t *lock) hal_spinlockSet(&threads_common.spinlock, &sc); - current = _proc_current(); + current = proc_current(); LIB_ASSERT(LIST_BELONGS(&owner->locks, lock) != 0, "lock: %s, owner pid: %d, owner tid: %d, lock is not on the list", lock->name, (owner->process != NULL) ? process_getPid(owner->process) : 0, proc_getTid(owner)); diff --git a/proc/threads.h b/proc/threads.h index a4b1f6324..580f1532e 100644 --- a/proc/threads.h +++ b/proc/threads.h @@ -85,6 +85,7 @@ typedef struct _thread_t { cpu_context_t *context; cpu_context_t *longjmpctx; + excjmp_context_t *excjmpctx; } thread_t; @@ -205,6 +206,12 @@ extern time_t proc_nextWakeup(void); extern void proc_longjmp(cpu_context_t *ctx); +extern void threads_setexcjmp(excjmp_context_t *ctx, excjmp_context_t **oldctx); + + +extern excjmp_context_t *threads_getexcjmp(void); + + extern void proc_threadsDump(unsigned int priority);