From 5f5461879c73720359e87fa41cbfe8c452f5155e Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Tue, 17 Aug 2021 11:36:50 +0000 Subject: Added missing header declarations, FlushCache, misc library bugfixes --- libpsn00b/libc/start.c | 181 +++++++++++++++++++++++++------------------------ 1 file changed, 93 insertions(+), 88 deletions(-) (limited to 'libpsn00b/libc/start.c') diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c index 354ebb9..c5872df 100644 --- a/libpsn00b/libc/start.c +++ b/libpsn00b/libc/start.c @@ -1,110 +1,115 @@ -#include +/* + * PSn00bSDK startup code + * (C) 2021 Lameguy64, spicyjpeg - MPL licensed + */ + +#include #include #include -#define load_gp() __asm__ volatile ( \ - "la $gp, _gp;" ) - -extern int _end; -extern int main(int argc, const char* argv[]); +#define KERNEL_ARG_STRING ((const char *) 0x80000180) +#define KERNEL_RETURN_VALUE ((volatile int *) 0x8000dffc) -void _mem_init(void); +/* Argument parsing */ -int __argc; +int32_t __argc; const char **__argv; -static const char *_arg_ptrs_int[8]; -static char _arg_buff[132]; +#define ARGC_MAX 16 -static void _call_global_ctors(void) -{ - extern void (*__CTOR_LIST__[])(void); +static const char *_argv_buffer[ARGC_MAX]; +static char _arg_string_buffer[132]; - // Constructors are called in reverse order of the list - int i; - for (i = (int)__CTOR_LIST__[0]; i >= 1; i--) { - // Each function handles one or more destructor (within - // file scope) - __CTOR_LIST__[i](); +static void _parse_kernel_args() { + // Copy the argument string from kernel memory into a private buffer (which + // won't be cleared or deallocated) and trim it at the first newline. + memset(_arg_string_buffer, 0, 132); + strncpy(_arg_string_buffer, KERNEL_ARG_STRING, 128); + + for (char *ptr = _arg_string_buffer; *ptr; ptr++) { + if ((*ptr == '\r') || (*ptr == '\n')) { + *ptr = 0; + break; + } } -} -static void _call_global_dtors(void) -{ - extern void (*__DTOR_LIST__[])(void); + __argv = _argv_buffer; + for (__argc = 0; __argc < ARGC_MAX; __argc++) { + const char *ptr; + if (!__argc) + ptr = strtok(_arg_string_buffer, " "); + else + ptr = strtok(0, " "); - /* Destructors in forward order */ - int i; - for (i = 0; i < (int)__DTOR_LIST__[0]; i++) { - /* Each function handles one or more destructor (within - * file scope) */ - __DTOR_LIST__[i + 1](); + _argv_buffer[__argc] = ptr; + if (!ptr) + break; } } -void _parse_args( int argc, const char *args[] ) -{ - int i; - char *c,*s; - - memset( _arg_buff, 0, 132 ); - - if( !args ) - { - // Use arguments from kernel if args is NULL - strncpy( _arg_buff, (char*)0x180, 128 ); - - // Clean-up args froom stray line-ends - while( ( c = strrchr( _arg_buff, '\r' ) ) || - ( c = strrchr( _arg_buff, '\n' ) ) ) - *c = 0; - } - else - { - __argc = argc; - __argv = args; - return; - } - - __argc = 0; - for( i=0; i<8; i++ ) - _arg_ptrs_int[i] = 0; - - s = _arg_buff; - while( c = strtok( s, " " ) ) - { - _arg_ptrs_int[__argc] = c; - __argc++; - s = NULL; - if( __argc >= 8 ) - break; - } - - __argv = _arg_ptrs_int; - -} /* parse_args */ +/* Main */ + +// How much space at the end of RAM to leave for the stack (instead of using it +// as heap). By default 128 KB are reserved for the stack, but this constant +// can be overridden in main.c (or anywhere else) simply by redeclaring it +// without the weak attribute. +const int32_t __attribute__((weak)) STACK_MAX_SIZE = 0x20000; -void _start( int argc, const char *args[] ) -{ - // Load GP address - load_gp(); +// These are defined by the linker script. Note that these are *NOT* pointers, +// they are virtual symbols whose location matches their value. The simplest +// way to turn them into pointers is to declare them as arrays, so here we go. +extern uint8_t __text_start[]; +extern uint8_t __bss_start[]; +extern uint8_t _end[]; +//extern uint8_t _gp[]; + +extern void (*__CTOR_LIST__[])(void); +extern void (*__DTOR_LIST__[])(void); + +extern int32_t main(int32_t argc, const char* argv[]); + +// Even though _start() usually takes no arguments, this implementation allows +// parent executables to pass args directly to child executables without having +// to overwrite the arg strings in kernel RAM. +void _start(int32_t override_argc, const char **override_argv) { + __asm__ volatile("la $gp, _gp;"); // Mem init assembly function (clears BSS and InitHeap to _end which is // not possible to do purely in C because the linker complains about // relocation truncated to fit: R_MIPS_GPREL16 against `_end' // Workaround is to do it in assembly because la pseudo-op doesn't use // stupid gp relative addressing - _mem_init(); - - // process command line arguments - _parse_args( argc, args ); - - _call_global_ctors(); - - *((int*)0x8000DFFC) = main( __argc, __argv ); - - _call_global_dtors(); - - // Set return value to kernel return value area - -} /* _start */ \ No newline at end of file + //_mem_init(); + + // Clear BSS 4 bytes at a time. BSS is always aligned to 4 bytes by the + // linker script. + for (uint32_t *i = (uint32_t *) __bss_start; i < (uint32_t *) _end; i++) + *i = 0; + + // Calculate how much RAM is available after the loaded executable and + // initialize heap accordingly. + void *exe_end = _end + 4; + unsigned int exe_size = (unsigned int) exe_end - (unsigned int) __text_start; + InitHeap(exe_end, 0x200000 - (exe_size + STACK_MAX_SIZE)); + + if (override_argv) { + __argc = override_argc; + __argv = override_argv; + } else { + _parse_kernel_args(); + } + + // Call the global constructors (if any) to initialize global objects + // before calling main(). Constructors are put by the linker script in a + // length-prefixed array in reverse order. + for (uint32_t i = (uint32_t) __CTOR_LIST__[0]; i >= 1; i--) + __CTOR_LIST__[i](); + + // Store main()'s return value into the kernel return value area (for child + // executables). + *KERNEL_RETURN_VALUE = main(__argc, __argv); + + // Call global destructors (in forward order). + for (uint32_t i = 0; i < (uint32_t) __DTOR_LIST__[0]; i++) + __DTOR_LIST__[i + 1](); +} -- cgit v1.2.3