Skip to content

Commit

Permalink
Make sure FPSCR is properly initialized
Browse files Browse the repository at this point in the history
This is a potentially breaking change as the register was left with an unpredictable/unspecified value.

Config: default NaN mode enabled, flush-to-zero enabled, and round to nearest.
  • Loading branch information
TuxSH committed Apr 12, 2022
1 parent c36d9cc commit 1168687
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 24 deletions.
13 changes: 13 additions & 0 deletions libctru/source/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,20 @@ typedef struct
bool srv_blocking_policy;
} ThreadVars;

struct Thread_tag
{
Handle handle;
ThreadFunc ep;
void* arg;
int rc;
bool detached, finished;
struct _reent reent;
void* stacktop;
};

static inline ThreadVars* getThreadVars(void)
{
return (ThreadVars*)getThreadLocalStorage();
}

void initThreadVars(struct Thread_tag *thread);
23 changes: 16 additions & 7 deletions libctru/source/system/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,27 @@ void __SYSCALL(exit)(int rc) {
__ctru_exit(rc);
}


void __system_initSyscalls(void)
void initThreadVars(struct Thread_tag *thread)
{

// Initialize thread vars for the main thread
ThreadVars* tv = getThreadVars();
tv->magic = THREADVARS_MAGIC;
tv->reent = _impure_ptr;
tv->thread_ptr = NULL;
tv->tls_tp = __tls_start-8; // ARM ELF TLS ABI mandates an 8-byte header
tv->reent = thread != NULL ? &thread->reent : _impure_ptr;
tv->thread_ptr = thread;
tv->tls_tp = (thread != NULL ? (u8*)thread->stacktop : __tls_start) - 8; // Arm ELF TLS ABI mandates an 8-byte header
tv->srv_blocking_policy = false;

// Kernel does not initialize fpscr at all, so we must do it ourselves
// https://developer.arm.com/documentation/ddi0360/f/vfp-programmers-model/vfp11-system-registers/floating-point-status-and-control-register--fpscr

// All flags clear, all interrupts disabled, all instruction scalar.
// As for the 3 below fields: default NaN mode, flush-to-zero both enabled & round to nearest.
__builtin_arm_set_fpscr(BIT(25) | BIT(24) | (0u << 22));
}

void __system_initSyscalls(void)
{
// Initialize thread vars for the main thread
initThreadVars(NULL);
u32 tls_size = __tdata_lma_end - __tdata_lma;
if (tls_size)
memcpy(__tls_start, __tdata_lma, tls_size);
Expand Down
18 changes: 1 addition & 17 deletions libctru/source/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@ extern const u8 __tdata_lma_end[];
extern u8 __tls_start[];
extern u8 __tls_end[];

struct Thread_tag
{
Handle handle;
ThreadFunc ep;
void* arg;
int rc;
bool detached, finished;
struct _reent reent;
void* stacktop;
};

static void __panic(void)
{
svcBreak(USERBREAK_PANIC);
Expand All @@ -28,12 +17,7 @@ static void __panic(void)
static void _thread_begin(void* arg)
{
Thread t = (Thread)arg;
ThreadVars* tv = getThreadVars();
tv->magic = THREADVARS_MAGIC;
tv->reent = &t->reent;
tv->thread_ptr = t;
tv->tls_tp = (u8*)t->stacktop-8; // ARM ELF TLS ABI mandates an 8-byte header
tv->srv_blocking_policy = false;
initThreadVars(t);
t->ep(t->arg);
threadExit(0);
}
Expand Down

0 comments on commit 1168687

Please sign in to comment.