Kernel: Support TLS allocation from userspace

This adds an allocate_tls syscall through which a userspace process
can request the allocation of a TLS region with a given size.

This will be used by the dynamic loader to allocate TLS for the main
executable & its libraries.
This commit is contained in:
Itamar 2020-10-10 12:17:07 +03:00 committed by Andreas Kling
parent 5b87904ab5
commit 9ca1a0731f
Notes: sideshowbarker 2024-07-19 00:52:01 +09:00
5 changed files with 57 additions and 1 deletions

View file

@ -194,7 +194,8 @@ namespace Kernel {
S(sysconf) \
S(set_process_name) \
S(disown) \
S(adjtime)
S(adjtime) \
S(allocate_tls)
namespace Syscall {

View file

@ -372,6 +372,7 @@ public:
int sys$recvfd(int sockfd);
long sys$sysconf(int name);
int sys$disown(ProcessID);
void* sys$allocate_tls(size_t);
template<bool sockname, typename Params>
int get_sock_or_peer_name(const Params&);

View file

@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <AK/WeakPtr.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/Process.h>
#include <Kernel/VM/PageDirectory.h>
@ -417,4 +418,46 @@ int Process::sys$munmap(void* addr, size_t size)
return -EINVAL;
}
void* Process::sys$allocate_tls(size_t size)
{
REQUIRE_PROMISE(stdio);
dbg() << "allocate TLS: " << size;
if (!size)
return (void*)-EINVAL;
if (!m_master_tls_region.is_null())
return (void*)-EEXIST;
if (thread_count() != 1)
return (void*)-EFAULT;
Thread* main_thread = nullptr;
for_each_thread([&main_thread](auto& thread) {
main_thread = &thread;
return IterationDecision::Break;
});
ASSERT(main_thread);
auto tls_region = allocate_region({}, size, String(), PROT_READ | PROT_WRITE);
if (!tls_region)
return (void*)-EFAULT;
m_master_tls_region = tls_region->make_weak_ptr();
dbg() << "master_tls_region: " << m_master_tls_region->vaddr();
m_master_tls_size = size;
m_master_tls_alignment = PAGE_SIZE;
auto tsr_result = main_thread->make_thread_specific_region({});
if (tsr_result.is_error())
return (void*)-EFAULT;
auto& tls_descriptor = Processor::current().get_gdt_entry(GDT_SELECTOR_TLS);
tls_descriptor.set_base(main_thread->thread_specific_data().as_ptr());
tls_descriptor.set_limit(main_thread->thread_specific_region_size());
return m_master_tls_region.unsafe_ptr()->vaddr().as_ptr();
}
}

View file

@ -87,4 +87,14 @@ int minherit(void* address, size_t size, int inherit)
int rc = syscall(SC_minherit, address, size, inherit);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
void* allocate_tls(size_t size)
{
int rc = syscall(SC_allocate_tls, size);
if (rc < 0 && -rc < EMAXERRNO) {
errno = -rc;
return MAP_FAILED;
}
return (void*)rc;
}
}

View file

@ -61,5 +61,6 @@ int mprotect(void*, size_t, int prot);
int set_mmap_name(void*, size_t, const char*);
int madvise(void*, size_t, int advice);
int minherit(void*, size_t, int inherit);
void* allocate_tls(size_t);
__END_DECLS