diff --git a/Pal/src/host/Linux/Makefile.am b/Pal/src/host/Linux/Makefile.am index 7cc7c235..fb1d7e0c 100644 --- a/Pal/src/host/Linux/Makefile.am +++ b/Pal/src/host/Linux/Makefile.am @@ -8,7 +8,6 @@ AR = ar rcs LD = ld CFLAGS = -Wall -fPIC -O2 -std=gnu99 -fgnu89-inline -U_FORTIFY_SOURCE \ - -fno-omit-frame-pointer \ -fno-stack-protector -fno-builtin ASFLAGS = -DPIC -DSHARED -fPIC -DASSEMBLER -Wa,--noexecstack \ -x assembler-with-cpp diff --git a/Pal/src/host/Linux/db_exception.c b/Pal/src/host/Linux/db_exception.c index 0c77cc57..d2d86fe0 100644 --- a/Pal/src/host/Linux/db_exception.c +++ b/Pal/src/host/Linux/db_exception.c @@ -29,6 +29,7 @@ #include "pal.h" #include "pal_internal.h" #include "pal_linux.h" +#include "pal_debug.h" #include "pal_error.h" #include "pal_security.h" #include "api.h" @@ -114,14 +115,8 @@ typedef struct { PAL_IDX event_num; PAL_CONTEXT context; ucontext_t * uc; - PAL_PTR eframe; } PAL_EVENT; -#define save_return_point(ptr) \ - asm volatile ("leaq 0(%%rip), %%rax\r\n" \ - "movq %%rax, %0\r\n" \ - : "=b"(ptr) :: "memory", "rax") - static int get_event_num (int signum) { switch(signum) { @@ -136,8 +131,7 @@ static int get_event_num (int signum) } void _DkGenericEventTrigger (PAL_IDX event_num, PAL_EVENT_HANDLER upcall, - PAL_NUM arg, struct pal_frame * frame, - ucontext_t * uc, void * eframe) + PAL_NUM arg, ucontext_t * uc) { PAL_EVENT event; event.event_num = event_num; @@ -145,31 +139,13 @@ void _DkGenericEventTrigger (PAL_IDX event_num, PAL_EVENT_HANDLER upcall, if (uc) memcpy(&event.context, uc->uc_mcontext.gregs, sizeof(PAL_CONTEXT)); - if (frame) { - event.context.r15 = frame->arch.r15; - event.context.r14 = frame->arch.r14; - event.context.r13 = frame->arch.r13; - event.context.r12 = frame->arch.r12; - event.context.rdi = frame->arch.rdi; - event.context.rsi = frame->arch.rsi; - event.context.rbx = frame->arch.rbx; - /* find last frame */ - event.context.rsp = frame->arch.rbp + sizeof(unsigned long) * 2; - event.context.rbp = ((unsigned long *) frame->arch.rbp)[0]; - event.context.rip = ((unsigned long *) frame->arch.rbp)[1]; - /* making rax = 0 to tell the caller that this PAL call failed */ - event.context.rax = 0; - } - event.uc = uc; - event.eframe = eframe; (*upcall) ((PAL_PTR) &event, arg, &event.context); } static bool _DkGenericSignalHandle (int event_num, siginfo_t * info, - struct pal_frame * frame, - ucontext_t * uc, void * eframe) + ucontext_t * uc) { PAL_EVENT_HANDLER upcall = _DkGetExceptionHandler(event_num); @@ -181,133 +157,113 @@ static bool _DkGenericSignalHandle (int event_num, siginfo_t * info, event_num == PAL_EVENT_ILLEGAL) arg = (PAL_NUM) (info ? info->si_addr : 0); - _DkGenericEventTrigger(event_num, upcall, arg, frame, uc, eframe); + _DkGenericEventTrigger(event_num, upcall, arg, uc); return true; } return false; } -#define ADDR_IN_PAL(addr) \ - ((void *) (addr) > TEXT_START && (void *) (addr) < TEXT_END) - -/* This function walks the stack to find the PAL_FRAME - * that was saved upon entry to the PAL, if an exception/interrupt - * comes in during a PAL call. This is needed to support the behavior that an - * exception in the PAL has Unix-style, EAGAIN semantics. - * - * The PAL_FRAME is supposed to be in the first PAL frame, and we look for - * it by matching a special magic number, that should only appear on the stack - * once. - * - * If an exception comes in while we are not in the PAL, this PAL_FRAME won't - * exist, and it is ok to return NULL. - */ -static struct pal_frame * get_frame (ucontext_t * uc) -{ - unsigned long rip = uc->uc_mcontext.gregs[REG_RIP]; - unsigned long rbp = uc->uc_mcontext.gregs[REG_RBP]; - unsigned long last_rbp = rbp - 64; - - if (!ADDR_IN_PAL(rip)) - return NULL; - - while (ADDR_IN_PAL(((unsigned long *) rbp)[1])) { - last_rbp = rbp; - rbp = *(unsigned long *) rbp; - } - - /* search frame record in the top frame of PAL */ - for (unsigned long ptr = rbp - sizeof(unsigned long) ; - ptr > last_rbp ; ptr -= 8) { - struct pal_frame * frame = (struct pal_frame *) ptr; - if (frame->identifier == PAL_FRAME_IDENTIFIER) - return frame; - } - - return NULL; -} - -static void return_frame (struct pal_frame * frame, int err) -{ - if (err) - _DkRaiseFailure(err); - - __clear_frame(frame); - arch_restore_frame(&frame->arch); - - asm volatile ("xor %rax, %rax\r\n" - "leaveq\r\n" - "retq\r\n"); -} - -#if BLOCK_SIGFAULT == 1 -static char exception_msg[24] = "--- SIGSEGV --- [ ]\n"; -static volatile bool cont_exec = false; -#endif - static void _DkGenericSighandler (int signum, siginfo_t * info, struct ucontext * uc) { -#if BLOCK_SIGFUALT == 1 - /* reseurrect this code if signal handler if giving segmentation fault */ - if (signum == SIGSEGV) { - int pid = INLINE_SYSCALL(getpid, 0); - exception_msg[17] = '0' + pid / 10000; - exception_msg[18] = '0' + (pid / 1000) % 10; - exception_msg[19] = '0' + (pid / 100) % 10; - exception_msg[20] = '0' + (pid / 10) % 10; - exception_msg[21] = '0' + pid % 10; - INLINE_SYSCALL(write, 3, 1, exception_msg, 24); - while(!cont_exec); - } -#endif - - struct pal_frame * frame = get_frame(uc); - void * eframe; - - if (signum == SIGCONT && frame && frame->func == DkObjectsWaitAny) - return; - - asm volatile ("movq %%rbp, %0" : "=r"(eframe)); - - if (frame && frame->func != &_DkGenericSighandler && - signum != SIGCONT && - signum != SIGINT && - signum != SIGTERM) { - return_frame(frame, PAL_ERROR_BADADDR); - return; - } - int event_num = get_event_num(signum); if (event_num == -1) return; - _DkGenericSignalHandle(event_num, info, frame, uc, eframe); + uintptr_t rip = uc->uc_mcontext.gregs[REG_RIP]; + if (ADDR_IN_PAL(rip)) { + // We expect none of the memory faults, illegal instructions, or arithmetic exceptions + // will happen in PAL. If these exceptions happen in PAL, exit the thread with loud warning. + int pid = INLINE_SYSCALL(getpid, 0); + int tid = INLINE_SYSCALL(gettid, 0); + const char * name = "exception"; + switch(event_num) { + case PAL_EVENT_DIVZERO: name = "div-by-zero exception"; break; + case PAL_EVENT_MEMFAULT: name = "memory fault"; break; + case PAL_EVENT_ILLEGAL: name = "illegal instruction"; break; + } + + printf("*** An unexpected %s occurred inside PAL. Exiting the thread. " + "(PID = %d, TID = %d, RIP = +%p) ***\n", + name, pid, tid, rip - (uintptr_t) TEXT_START); + _DkThreadExit(); + return; + } + + _DkGenericSignalHandle(event_num, info, uc); } static void _DkTerminateSighandler (int signum, siginfo_t * info, struct ucontext * uc) { - struct pal_frame * frame = get_frame(uc); - void * eframe; - - asm volatile ("movq %%rbp, %0" : "=r"(eframe)); - int event_num = get_event_num(signum); if (event_num == -1) return; - if (!_DkGenericSignalHandle(event_num, NULL, frame, uc, eframe)) + uintptr_t rip = uc->uc_mcontext.gregs[REG_RIP]; + + // If the signal arrives in the middle of a PAL call, add the event + // to pending in the current TCB. + if (ADDR_IN_PAL(rip)) { + PAL_TCB * tcb = get_tcb(); + assert(tcb); + if (!tcb->pending_event) { + // Use the preserved pending event slot + tcb->pending_event = event_num; + } else { + // If there is already a pending event, add the new event to the queue. + // (a relatively rare case.) + struct event_queue * ev = malloc(sizeof(*ev)); + if (!ev) + return; + + INIT_LIST_HEAD(ev, list); + ev->event_num = event_num; + listp_add_tail(ev, &tcb->pending_queue, list); + } + return; + } + + // Call the event handler. If there is no handler, terminate the thread + // unless it is a resuming event (then ignore the event). + if (!_DkGenericSignalHandle(event_num, NULL, uc) && event_num != PAL_EVENT_RESUME) _DkThreadExit(); } static void _DkPipeSighandler (int signum, siginfo_t * info, struct ucontext * uc) { + uintptr_t rip = uc->uc_mcontext.gregs[REG_RIP]; + assert(ADDR_IN_PAL(rip)); // This signal can only happens inside PAL return; } +/* + * __check_pending_event(): checks the existence of a pending event in the TCB + * and handles the event consequently. + */ +void __check_pending_event (void) +{ + PAL_TCB * tcb = get_tcb(); + assert(tcb); + if (tcb->pending_event) { + int event = tcb->pending_event; + tcb->pending_event = 0; + _DkGenericSignalHandle(event, NULL, NULL); + + if (!listp_empty(&tcb->pending_queue)) { + // If there are more than one pending events, process them from the queue + struct event_queue * ev, * n; + listp_for_each_entry_safe(ev, n, &tcb->pending_queue, list) { + listp_del(ev, &tcb->pending_queue, list); + _DkGenericSignalHandle(ev->event_num, NULL, NULL); + free(ev); + } + } + } +} + void _DkRaiseFailure (int error) { PAL_EVENT_HANDLER upcall = _DkGetExceptionHandler(PAL_EVENT_FAILURE); @@ -318,7 +274,6 @@ void _DkRaiseFailure (int error) PAL_EVENT event; event.event_num = PAL_EVENT_FAILURE; event.uc = NULL; - event.eframe = NULL; (*upcall) ((PAL_PTR) &event, error, NULL); } @@ -340,7 +295,7 @@ struct signal_ops on_signals[] = { [PAL_EVENT_SUSPEND] = { .signum = { SIGINT, 0 }, .handler = _DkTerminateSighandler }, [PAL_EVENT_RESUME] = { .signum = { SIGCONT, 0 }, - .handler = _DkGenericSighandler }, + .handler = _DkTerminateSighandler }, }; static int _DkPersistentSighandlerSetup (int event_num) @@ -389,28 +344,6 @@ err: void _DkExceptionReturn (void * event) { PAL_EVENT * e = event; - - if (e->eframe) { - struct pal_frame * frame = (struct pal_frame *) e->eframe; - int err = 0; - - switch (e->event_num) { - case PAL_EVENT_MEMFAULT: - err = PAL_ERROR_BADADDR; - break; - case PAL_EVENT_QUIT: - case PAL_EVENT_SUSPEND: - case PAL_EVENT_RESUME: - err = PAL_ERROR_INTERRUPTED; - break; - } - - if (err) - _DkRaiseFailure(err); - - __clear_frame(frame); - } - if (e->uc) { /* copy the context back to ucontext */ memcpy(e->uc->uc_mcontext.gregs, &e->context, sizeof(PAL_CONTEXT)); diff --git a/Pal/src/host/Linux/db_main.c b/Pal/src/host/Linux/db_main.c index 2259bbdf..fee49ef3 100644 --- a/Pal/src/host/Linux/db_main.c +++ b/Pal/src/host/Linux/db_main.c @@ -229,6 +229,26 @@ void pal_linux_main (void * args) init_slab_mgr(pagesz); + first_thread = malloc(HANDLE_SIZE(thread)); + if (!first_thread) + init_fail(PAL_ERROR_NOMEM, "Out of memory"); + SET_HANDLE_TYPE(first_thread, thread); + first_thread->thread.tid = INLINE_SYSCALL(gettid, 0); + + void * alt_stack = NULL; + _DkVirtualMemoryAlloc(&alt_stack, ALT_STACK_SIZE, 0, PAL_PROT_READ|PAL_PROT_WRITE); + if (!alt_stack) + init_fail(PAL_ERROR_NOMEM, "Out of memory"); + + // Initialize TCB at the top of the alternative stack. + PAL_TCB * tcb = alt_stack + ALT_STACK_SIZE - sizeof(PAL_TCB); + tcb->self = tcb; + tcb->handle = first_thread; + tcb->alt_stack = alt_stack; // Stack bottom + tcb->callback = NULL; + tcb->param = NULL; + pal_thread_init(tcb); + setup_pal_map(&pal_map); #if USE_VDSO_GETTIME == 1 @@ -287,10 +307,6 @@ done_init: return; } - first_thread = malloc(HANDLE_SIZE(thread)); - SET_HANDLE_TYPE(first_thread, thread); - first_thread->thread.tid = linux_state.pid; - signal_setup(); /* call to main function */ diff --git a/Pal/src/host/Linux/db_misc.c b/Pal/src/host/Linux/db_misc.c index 1d013f15..d70ab3dd 100644 --- a/Pal/src/host/Linux/db_misc.c +++ b/Pal/src/host/Linux/db_misc.c @@ -186,7 +186,7 @@ int _DkSegmentRegisterSet (int reg, const void * addr) if (reg == PAL_SEGMENT_FS) { ret = INLINE_SYSCALL(arch_prctl, 2, ARCH_SET_FS, addr); } else if (reg == PAL_SEGMENT_GS) { - ret = INLINE_SYSCALL(arch_prctl, 2, ARCH_SET_GS, addr); + return -PAL_ERROR_DENIED; } else { return -PAL_ERROR_INVAL; } @@ -216,7 +216,8 @@ int _DkSegmentRegisterGet (int reg, void ** addr) if (reg == PAL_SEGMENT_FS) { ret = INLINE_SYSCALL(arch_prctl, 2, ARCH_GET_FS, &ret_addr); } else if (reg == PAL_SEGMENT_GS) { - ret = INLINE_SYSCALL(arch_prctl, 2, ARCH_GET_GS, &ret_addr); + // The GS segment is used for the internal TCB of PAL + return -PAL_ERROR_DENIED; } else { return -PAL_ERROR_INVAL; } diff --git a/Pal/src/host/Linux/db_mutex.c b/Pal/src/host/Linux/db_mutex.c index baa0ef3e..4e9e55eb 100644 --- a/Pal/src/host/Linux/db_mutex.c +++ b/Pal/src/host/Linux/db_mutex.c @@ -197,6 +197,16 @@ void _DkMutexRelease (PAL_HANDLE handle) return; } +int _DkInternalLock (PAL_LOCK* lock) { + while (_DkMutexLock(lock) < 0); // Retry the lock if being interrupted by signals + return 0; +} + +int _DkInternalUnlock (PAL_LOCK* lock) { + _DkMutexUnlock(lock); + return 0; +} + static int mutex_wait (PAL_HANDLE handle, uint64_t timeout) { return _DkMutexAcquireTimeout(handle, timeout); diff --git a/Pal/src/host/Linux/db_threading.c b/Pal/src/host/Linux/db_threading.c index 42df1574..58c4614b 100644 --- a/Pal/src/host/Linux/db_threading.c +++ b/Pal/src/host/Linux/db_threading.c @@ -39,12 +39,46 @@ #include #include -/* default size of a new thread stack */ -/* DEP 2/4/17: There is enough stuff allocated on the PAL stack now - * that we need two pages in Linux host mode. In SGX mode, - * the enclave/non-clave split makes 1 page in/1 out sufficient. +#if defined(__i386__) +#include +#else +#include +#endif + +/* + * pal_thread_init(): An initialization wrapper of a newly-created thread (including + * the first thread). This function accepts a TCB pointer to be set to the GS register + * of the thread. The rest of the TCB is used as the alternative stack for signal + * handling. */ -#define THREAD_STACK_SIZE (pal_state.alloc_align * 2) +int pal_thread_init (void * tcbptr) +{ + PAL_TCB * tcb = tcbptr; + int ret; + + ret = INLINE_SYSCALL(arch_prctl, 2, ARCH_SET_GS, tcb); + if (IS_ERR(ret)) + return -ERRNO(ret); + + if (tcb->alt_stack) { + // Align stack to 16 bytes + void * alt_stack_top = (void *) ((uint64_t) tcb & ~16); + assert(alt_stack_top > tcb->alt_stack); + stack_t ss; + ss.ss_sp = alt_stack_top; + ss.ss_flags = 0; + ss.ss_size = alt_stack_top - tcb->alt_stack; + + ret = INLINE_SYSCALL(sigaltstack, 2, &ss, NULL); + if (IS_ERR(ret)) + return -ERRNO(ret); + } + + if (tcb->callback) + return (*tcb->callback) (tcb->param); + + return 0; +} /* _DkThreadCreate for internal use. Create an internal thread inside the current process. The arguments callback and param @@ -52,35 +86,51 @@ int _DkThreadCreate (PAL_HANDLE * handle, int (*callback) (void *), const void * param, int flags) { - void * child_stack = NULL; + void * stack = NULL; + int ret = _DkVirtualMemoryAlloc(&stack, THREAD_STACK_SIZE + ALT_STACK_SIZE, + 0, PAL_PROT_READ|PAL_PROT_WRITE); + if (ret < 0) + return ret; - if (_DkVirtualMemoryAlloc(&child_stack, THREAD_STACK_SIZE, 0, - PAL_PROT_READ|PAL_PROT_WRITE) < 0) - return -PAL_ERROR_NOMEM; + void * child_stack = stack + THREAD_STACK_SIZE; - /* move child_stack to the top of stack. */ - child_stack += THREAD_STACK_SIZE; + PAL_HANDLE hdl = malloc(HANDLE_SIZE(thread)); + if (!hdl) { + ret = -ENOMEM; + goto err; + } + SET_HANDLE_TYPE(hdl, thread); + + // Initialize TCB at the top of the alternative stack. + PAL_TCB * tcb = child_stack + ALT_STACK_SIZE - sizeof(PAL_TCB); + tcb->self = tcb; + tcb->handle = hdl; + tcb->alt_stack = child_stack; // Stack bottom + tcb->callback = callback; + tcb->param = (void *) param; /* align child_stack to 16 */ child_stack = (void *) ((uintptr_t) child_stack & ~16); - int tid = 0; - int ret = clone(callback, child_stack, + ret = clone(pal_thread_init, child_stack, CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SYSVSEM| CLONE_THREAD|CLONE_SIGHAND|CLONE_PTRACE| CLONE_PARENT_SETTID, - param, &tid, NULL); - if (IS_ERR(ret)) - return -PAL_ERROR_DENIED; + (void *) tcb, &hdl->thread.tid, NULL); + + if (IS_ERR(ret)) { + ret = -PAL_ERROR_DENIED; + goto err; + } - PAL_HANDLE hdl = malloc(HANDLE_SIZE(thread)); - SET_HANDLE_TYPE(hdl, thread); - hdl->thread.tid = tid; *handle = hdl; - - /* _DkThreadAdd(tid); */ - return 0; +err: + if (stack) + _DkVirtualMemoryFree(stack, THREAD_STACK_SIZE + ALT_STACK_SIZE); + if (hdl) + free(hdl); + return ret; } int _DkThreadDelayExecution (unsigned long * duration) diff --git a/Pal/src/host/Linux/pal_host.h b/Pal/src/host/Linux/pal_host.h index 1e9e9f9b..7aca18de 100644 --- a/Pal/src/host/Linux/pal_host.h +++ b/Pal/src/host/Linux/pal_host.h @@ -53,9 +53,6 @@ typedef struct mutex_handle { #define LOCK_INIT MUTEX_HANDLE_INIT #define INIT_LOCK(lock) INIT_MUTEX_HANDLE(lock); -#define _DkInternalLock _DkMutexLock -#define _DkInternalUnlock _DkMutexUnlock - /* Locking and unlocking of Mutexes */ int _DkMutexLock (struct mutex_handle * mut); int _DkMutexLockTimeout (struct mutex_handle * mut, uint64_t timeout); @@ -183,115 +180,12 @@ typedef struct pal_handle #define HANDLE_TYPE(handle) ((handle)->hdr.type) -struct arch_frame { -#ifdef __x86_64__ - uint64_t rsp, rbp, rbx, rsi, rdi, r12, r13, r14, r15; -#else -# error "unsupported architecture" -#endif -}; +extern void __check_pending_event (void); -#ifdef __x86_64__ -# define store_register(reg, var) \ - asm volatile ("movq %%" #reg ", %0" : "=a" (var) :: "memory"); +#define LEAVE_PAL_CALL() do { __check_pending_event(); } while (0) -# define store_register_in_frame(reg, f) store_register(reg, (f)->reg) - -# define arch_store_frame(f) \ - store_register_in_frame(rsp, f) \ - store_register_in_frame(rbp, f) \ - store_register_in_frame(rbx, f) \ - store_register_in_frame(rsi, f) \ - store_register_in_frame(rdi, f) \ - store_register_in_frame(r12, f) \ - store_register_in_frame(r13, f) \ - store_register_in_frame(r14, f) \ - store_register_in_frame(r15, f) - -# define restore_register(reg, var, clobber...) \ - asm volatile ("movq %0, %%" #reg :: "g" (var) : "memory", ##clobber); - -# define restore_register_in_frame(reg, f) \ - restore_register(reg, (f)->reg, \ - "r15", "r14", "r13", "r12", "rdi", "rsi", "rbx") - -# define arch_restore_frame(f) \ - restore_register_in_frame(r15, f) \ - restore_register_in_frame(r14, f) \ - restore_register_in_frame(r13, f) \ - restore_register_in_frame(r12, f) \ - restore_register_in_frame(rdi, f) \ - restore_register_in_frame(rsi, f) \ - restore_register_in_frame(rbx, f) \ - restore_register_in_frame(rbp, f) \ - restore_register_in_frame(rsp, f) -#else /* __x86_64__ */ -# error "unsupported architecture" -#endif - -#define PAL_FRAME_IDENTIFIER (0xdeaddeadbeefbeef) - -struct pal_frame { - volatile uint64_t identifier; - void * func; - const char * funcname; - struct arch_frame arch; -}; - -/* When a PAL call is issued, a special PAL_FRAME is placed on the stack. - * This stores both a magic identifier, debugging information, - * as well as callee-saved state. This is used as a way to deal - * with PAL-internal failures where the goal is to exit the PAL and return a - * failure. - * - * Arguably, an alternative is to unwind the stack and handle error cases at - * each stage. In general, this is probably more robust, but would take work - * in the short term. The one exception where the current strategy is - * probably better is when the PAL gets in a state where the code is - * unrecoverable, but ideally, this shouldn't happen. - */ - -/* DEP 12/25/17: This frame storage thing is important to mark volatile. - * The compiler should not optimize out any of these changes, and - * because some accesses can happen during an exception, these are not - * visible to the compiler in an otherwise stack-local variable (so the - * compiler will try to optimize out these assignments. - */ -static inline -void __store_frame (volatile struct pal_frame * frame, - void * func, const char * funcname) -{ - arch_store_frame(&frame->arch) - frame->func = func; - frame->funcname = funcname; - asm volatile ("nop" ::: "memory"); - frame->identifier = PAL_FRAME_IDENTIFIER; -} - -#define ENTER_PAL_CALL(name) \ - struct pal_frame frame; \ - __store_frame(&frame, &(name), #name) - - -static inline -void __clear_frame (volatile struct pal_frame * frame) -{ - if (frame->identifier == PAL_FRAME_IDENTIFIER) { - asm volatile ("nop" ::: "memory"); - frame->identifier = 0; - } -} - -#define LEAVE_PAL_CALL() \ - do { \ - __clear_frame(&frame); \ - } while (0) - -#define LEAVE_PAL_CALL_RETURN(retval) \ - do { \ - __clear_frame(&frame); \ - return (retval); \ - } while (0) +#define LEAVE_PAL_CALL_RETURN(retval) \ + do { __check_pending_event(); return (retval); } while (0) #if TRACE_HEAP_LEAK == 1 diff --git a/Pal/src/host/Linux/pal_linux.h b/Pal/src/host/Linux/pal_linux.h index b2c5ccf2..a571e880 100644 --- a/Pal/src/host/Linux/pal_linux.h +++ b/Pal/src/host/Linux/pal_linux.h @@ -25,6 +25,7 @@ #include "pal.h" #include "pal_internal.h" #include "pal_linux_error.h" +#include "list.h" #define PAL_LOADER RUNTIME_FILE("pal-Linux") @@ -172,4 +173,35 @@ extern char __text_start, __text_end, __data_start, __data_end; #define DATA_START (void *) (&__text_start) #define DATA_END (void *) (&__text_end) +#define ADDR_IN_PAL(addr) \ + ((void *) (addr) > TEXT_START && (void *) (addr) < TEXT_END) + +DEFINE_LIST(event_queue); +struct event_queue { + LIST_TYPE(event_queue) list; + int event_num; +}; + +DEFINE_LISTP(event_queue); +typedef struct pal_tcb { + struct pal_tcb * self; + int pending_event; + LISTP_TYPE(event_queue) pending_queue; + PAL_HANDLE handle; + void * alt_stack; + int (*callback) (void *); + void * param; +} PAL_TCB; + +int pal_thread_init (void * tcbptr); + +static inline PAL_TCB * get_tcb (void) +{ + PAL_TCB * tcb; + asm ("movq %%gs:%c1,%q0" + : "=r" (tcb) + : "i" (offsetof(PAL_TCB, self))); + return tcb; +} + #endif /* PAL_LINUX_H */ diff --git a/Pal/src/host/Linux/pal_linux_defs.h b/Pal/src/host/Linux/pal_linux_defs.h index 9d5347eb..94ac899f 100644 --- a/Pal/src/host/Linux/pal_linux_defs.h +++ b/Pal/src/host/Linux/pal_linux_defs.h @@ -7,6 +7,9 @@ #define USER_ADDRESS_RESERVED 0x100000000 #define USER_ADDRESS_LOWEST 0x10000 +#define THREAD_STACK_SIZE (PRESET_PAGESIZE * 2) +#define ALT_STACK_SIZE (PRESET_PAGESIZE) + /* internal wrap native pipe inside pipe streams */ #define USE_PIPE_SYSCALL 0