Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions libctru/source/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#define THREADVARS_MAGIC 0x21545624 // !TV$
#define FS_OVERRIDE_MAGIC 0x21465324 // !FS$

extern const size_t __tdata_align;
Comment thread
ian-h-chamberlain marked this conversation as resolved.
extern const u8 __tdata_lma[];
extern const u8 __tdata_lma_end[];
extern u8 __tls_start[];
extern u8 __tls_end[];

// Keep this structure under 0x80 bytes
typedef struct
{
Expand Down Expand Up @@ -48,3 +54,7 @@ static inline ThreadVars* getThreadVars(void)
}

void initThreadVars(struct Thread_tag *thread);

static inline size_t alignTo(const size_t base, const size_t align) {
return (base + (align - 1)) & ~(align - 1);
}
11 changes: 4 additions & 7 deletions libctru/source/system/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@

void __ctru_exit(int rc);

extern const u8 __tdata_lma[];
extern const u8 __tdata_lma_end[];
extern u8 __tls_start[];

struct _reent* __SYSCALL(getreent)()
{
ThreadVars* tv = getThreadVars();
Expand All @@ -43,7 +39,7 @@ int __SYSCALL(clock_gettime)(clockid_t clock_id, struct timespec *tp) {
tp->tv_nsec = (ms_since_epoch % 1000) * 1000000;
}
}
else if (clock_id == CLOCK_MONOTONIC)
else if (clock_id == CLOCK_MONOTONIC)
{
if (tp != NULL)
{
Expand All @@ -66,7 +62,7 @@ int __SYSCALL(clock_gettime)(clockid_t clock_id, struct timespec *tp) {
int __SYSCALL(clock_getres)(clockid_t clock_id, struct timespec *res) {
if (clock_id == CLOCK_REALTIME)
{
if (res != NULL)
if (res != NULL)
{
res->tv_sec = 0;
res->tv_nsec = 1000000;
Expand Down Expand Up @@ -185,6 +181,7 @@ void __system_initSyscalls(void)
// Initialize thread vars for the main thread
initThreadVars(NULL);
u32 tls_size = __tdata_lma_end - __tdata_lma;
size_t tdata_start = alignTo((size_t)__tls_start, __tdata_align);
if (tls_size)
memcpy(__tls_start, __tdata_lma, tls_size);
memcpy((void*)tdata_start, __tdata_lma, tls_size);
}
33 changes: 20 additions & 13 deletions libctru/source/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
#include <malloc.h>
#include <string.h>

extern const u8 __tdata_lma[];
extern const u8 __tdata_lma_end[];
extern u8 __tls_start[];
extern u8 __tls_end[];

static void __panic(void)
{
svcBreak(USERBREAK_PANIC);
Expand All @@ -24,18 +19,26 @@ static void _thread_begin(void* arg)

Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int prio, int core_id, bool detached)
{
size_t stackoffset = (sizeof(struct Thread_tag)+7)&~7;
size_t allocsize = stackoffset + ((stack_size+7)&~7);
// The stack must be 8-aligned at minimum.
size_t align = __tdata_align > 8 ? __tdata_align : 8;

size_t stackoffset = alignTo(sizeof(struct Thread_tag), align);
size_t allocsize = alignTo(stackoffset + stack_size, align);

size_t tlssize = __tls_end-__tls_start;
size_t tlsloadsize = __tdata_lma_end-__tdata_lma;
size_t tbsssize = tlssize-tlsloadsize;
size_t tbsssize = tlssize - tlsloadsize;

// memalign seems to have an implicit requirement that (size % align) == 0.
// Without this, it seems to return NULL whenever (align > 8).
size_t size = alignTo(allocsize + tlssize, align);

// Guard against overflow
if (allocsize < stackoffset) return NULL;
if ((allocsize-stackoffset) < stack_size) return NULL;
if ((allocsize+tlssize) < allocsize) return NULL;
if ((allocsize - stackoffset) < stack_size) return NULL;
if (size < allocsize) return NULL;

Thread t = (Thread)memalign(8,allocsize+tlssize);
Thread t = (Thread)memalign(align, size);
if (!t) return NULL;

t->ep = entrypoint;
Expand All @@ -44,10 +47,14 @@ Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int pri
t->finished = false;
t->stacktop = (u8*)t + allocsize;

// ThreadVars.tls_tp must be aligned correctly, so we bump tdata_start to
// ensure that after subtracting 8 bytes for the TLS header, it will be aligned.
size_t tdata_start = 8 + alignTo((size_t)t->stacktop - 8, align);

if (tlsloadsize)
memcpy(t->stacktop, __tdata_lma, tlsloadsize);
memcpy((void*)tdata_start, __tdata_lma, tlsloadsize);
if (tbsssize)
memset((u8*)t->stacktop+tlsloadsize, 0, tbsssize);
memset((void*)tdata_start + tlsloadsize, 0, tbsssize);

// Set up child thread's reent struct, inheriting standard file handles
_REENT_INIT_PTR(&t->reent);
Expand Down