diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 34e89fd2..60b1b1f1 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -209,7 +209,7 @@ namespace Kernel BAN::ErrorOr sys_set_gsbase(void*); BAN::ErrorOr sys_get_gsbase(); - BAN::ErrorOr sys_thread_create(void (*entry)(void*), void* arg); + BAN::ErrorOr sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size); BAN::ErrorOr sys_thread_exit(void* value); BAN::ErrorOr sys_thread_join(pid_t tid, void** value); BAN::ErrorOr sys_thread_getid(); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 5ff25f58..dcea5c51 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -3549,20 +3549,14 @@ namespace Kernel return Thread::current().get_gsbase(); } - BAN::ErrorOr Process::sys_thread_create(void (*entry)(void*), void* arg) + BAN::ErrorOr Process::sys_thread_create(void (*entry)(void*), void* arg, void* stack_base, size_t stack_size) { - auto userspace_stack = TRY(MemoryBackedRegion::create( - page_table(), - Thread::userspace_stack_size, - { Thread::userspace_stack_base, USERSPACE_END }, - MemoryRegion::Type::PRIVATE, - PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present, - O_RDWR - )); + const vaddr_t stack_vaddr = reinterpret_cast(stack_base); + if (stack_vaddr % PAGE_SIZE || stack_size % PAGE_SIZE) + return BAN::Error::from_errno(EINVAL); - const vaddr_t stack_vaddr = userspace_stack->vaddr(); - const size_t stack_size = userspace_stack->size(); - TRY(add_mapped_region(BAN::move(userspace_stack))); + auto* memory_region = TRY(validate_and_pin_pointer_access(stack_base, stack_size, true)); + BAN::ScopeGuard _0([memory_region] { if (memory_region) memory_region->unpin(); }); const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*); *reinterpret_cast(initial_stack_pointer) = arg; @@ -3577,7 +3571,7 @@ namespace Kernel )); thread->m_signal_block_mask = Thread::current().m_signal_block_mask; - LockGuard _(m_process_lock); + LockGuard _1(m_process_lock); TRY(m_threads.push_back(thread)); if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error()) diff --git a/userspace/libraries/LibC/include/bits/types/pthread_attr_t.h b/userspace/libraries/LibC/include/bits/types/pthread_attr_t.h index 84c1c108..26df7ebf 100644 --- a/userspace/libraries/LibC/include/bits/types/pthread_attr_t.h +++ b/userspace/libraries/LibC/include/bits/types/pthread_attr_t.h @@ -16,6 +16,7 @@ typedef struct int schedpolicy; int detachstate; int scope; + void* stackaddr; size_t stacksize; size_t guardsize; } pthread_attr_t; diff --git a/userspace/libraries/LibC/include/bits/types/uthread.h b/userspace/libraries/LibC/include/bits/types/uthread.h index 00e88eec..c0329591 100644 --- a/userspace/libraries/LibC/include/bits/types/uthread.h +++ b/userspace/libraries/LibC/include/bits/types/uthread.h @@ -49,6 +49,7 @@ struct uthread pid_t id; pthread_attr_t attr; int errno_; + int libc_owns_stack; int cancel_type; int cancel_state; volatile int canceled; diff --git a/userspace/libraries/LibC/pthread.cpp b/userspace/libraries/LibC/pthread.cpp index 8f3c1137..d2bf8889 100644 --- a/userspace/libraries/LibC/pthread.cpp +++ b/userspace/libraries/LibC/pthread.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,7 @@ static void _init_pthread() uthread->id = syscall(SYS_THREAD_GETID); uthread->attr = s_default_pthread_attr; uthread->errno_ = 0; + uthread->libc_owns_stack = false; uthread->cancel_type = PTHREAD_CANCEL_DEFERRED; uthread->cancel_state = PTHREAD_CANCEL_ENABLE; uthread->canceled = false; @@ -43,6 +45,11 @@ static void _init_pthread() memset(uthread->specific_keys, 0, sizeof(uthread->specific_keys)); memset(uthread->specific_vals, 0, sizeof(uthread->specific_vals)); + if (auto value = getauxval(AT_STACK_BASE)) + uthread->attr.stackaddr = reinterpret_cast(value); + if (auto value = getauxval(AT_STACK_SIZE)) + uthread->attr.stacksize = value; + signal(SIGCANCEL, &_pthread_cancel_handler); } @@ -120,6 +127,9 @@ static void free_uthread(uthread* uthread) munmap(reinterpret_cast(uthread->dtv[i]), size); } + if (uthread->libc_owns_stack) + munmap(static_cast(uthread->attr.stackaddr) - uthread->attr.guardsize, uthread->attr.guardsize + uthread->attr.stacksize); + uint8_t* tls_addr = reinterpret_cast(uthread) - uthread->master_tls_size; const size_t tls_size = uthread->master_tls_size + sizeof(struct uthread); munmap(tls_addr, tls_size); @@ -288,6 +298,8 @@ int pthread_attr_getguardsize(const pthread_attr_t* __restrict attr, size_t* __r int pthread_attr_setguardsize(pthread_attr_t* attr, size_t guardsize) { + if (auto rem = guardsize % getpagesize()) + guardsize += getpagesize() - rem; attr->guardsize = guardsize; return 0; } @@ -364,20 +376,22 @@ int pthread_attr_setscope(pthread_attr_t* attr, int contentionscope) int pthread_attr_getstack(const pthread_attr_t* __restrict attr, void** __restrict stackaddr, size_t* __restrict stacksize) { - (void)attr; - (void)stackaddr; - (void)stacksize; - dwarnln("TODO: pthread_attr_getstack"); - return ENOTSUP; + *stackaddr = attr->stackaddr; + *stacksize = attr->stacksize; + return 0; } int pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize) { - (void)attr; - (void)stackaddr; - (void)stacksize; - dwarnln("TODO: pthread_attr_setstack"); - return ENOTSUP; + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + if (reinterpret_cast(stackaddr) % getpagesize()) + return EINVAL; + if (stacksize % getpagesize()) + return EINVAL; + attr->stackaddr = stackaddr; + attr->stacksize = stacksize; + return 0; } int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __restrict stacksize) @@ -433,6 +447,7 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric .id = -1, .attr = attr ? *attr : s_default_pthread_attr, .errno_ = 0, + .libc_owns_stack = false, .cancel_type = PTHREAD_CANCEL_DEFERRED, .cancel_state = PTHREAD_CANCEL_ENABLE, .canceled = 0, @@ -442,6 +457,21 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric .dtv = { self->dtv[0] } }; + if (uthread->attr.stackaddr == nullptr) + { + ASSERT(uthread->attr.stacksize % getpagesize() == 0); + ASSERT(uthread->attr.guardsize % getpagesize() == 0); + + void* stack_addr = mmap(nullptr, uthread->attr.guardsize + uthread->attr.stacksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (stack_addr == nullptr) + goto pthread_create_error; + uthread->attr.stackaddr = static_cast(stack_addr) + uthread->attr.guardsize; + uthread->libc_owns_stack = true; + + if (uthread->attr.guardsize != 0 && mprotect(stack_addr, uthread->attr.guardsize, PROT_NONE) == -1) + goto pthread_create_error; + } + const uintptr_t self_addr = reinterpret_cast(self); const uintptr_t uthread_addr = reinterpret_cast(uthread); for (size_t i = 1; i <= self->master_tls_module_count; i++) @@ -451,7 +481,7 @@ int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restric result = uthread; } - if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info) == -1) + if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info, info->uthread->attr.stackaddr, info->uthread->attr.stacksize) == -1) goto pthread_create_error; if (thread)