aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2021-08-17 11:36:50 +0000
committerspicyjpeg <88942473+spicyjpeg@users.noreply.github.com>2021-08-17 11:36:50 +0000
commit5f5461879c73720359e87fa41cbfe8c452f5155e (patch)
tree9de8b0dcfcffa70fac7da91792772679af8341bb
parentacc1a959fe3c4bc5d5e91f1f31e182ff967008ca (diff)
downloadpsn00bsdk-5f5461879c73720359e87fa41cbfe8c452f5155e.tar.gz
Added missing header declarations, FlushCache, misc library bugfixes
-rw-r--r--libpsn00b/include/psxapi.h1
-rw-r--r--libpsn00b/include/psxgpu.h2
-rw-r--r--libpsn00b/include/stdio.h3
-rw-r--r--libpsn00b/libc/_mem_init.s20
-rw-r--r--libpsn00b/libc/malloc.s11
-rw-r--r--libpsn00b/libc/start.c181
-rw-r--r--libpsn00b/psxapi/sys/flushcache.s10
-rw-r--r--libpsn00b/psxspu/transfer.s3
8 files changed, 121 insertions, 110 deletions
diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h
index c366702..9e92568 100644
--- a/libpsn00b/include/psxapi.h
+++ b/libpsn00b/include/psxapi.h
@@ -180,6 +180,7 @@ void ChangeClearRCnt(int t, int m);
// Executable functions
int Exec(struct EXEC *exec, int argc, char **argv);
+void FlushCache(void);
void _boot(void);
diff --git a/libpsn00b/include/psxgpu.h b/libpsn00b/include/psxgpu.h
index ddb4522..f50b841 100644
--- a/libpsn00b/include/psxgpu.h
+++ b/libpsn00b/include/psxgpu.h
@@ -1,6 +1,8 @@
#ifndef __PSXGPU_H
#define __PSXGPU_H
+#include <sys/types.h>
+
// Low-level display parameters for DISPENV_RAW. A leftover from prototyping
#define DISP_WIDTH_256 0
#define DISP_WIDTH_320 1
diff --git a/libpsn00b/include/stdio.h b/libpsn00b/include/stdio.h
index cf1909d..97a2f5a 100644
--- a/libpsn00b/include/stdio.h
+++ b/libpsn00b/include/stdio.h
@@ -56,6 +56,9 @@ int vsprintf(char *string, const char *fmt, va_list ap);
int sprintf(char *string, const char *fmt, ...);
int snprintf(char *string, unsigned int size, const char *fmt, ...);
+int vsscanf(const char *str, const char *format, va_list ap);
+int sscanf(const char *str, const char *fmt, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/libpsn00b/libc/_mem_init.s b/libpsn00b/libc/_mem_init.s
deleted file mode 100644
index 672ac2f..0000000
--- a/libpsn00b/libc/_mem_init.s
+++ /dev/null
@@ -1,20 +0,0 @@
-.set noreorder
-
-.global _mem_init
-.type _mem_init, @function
-_mem_init:
-
-.section .text
-
-_mem_init:
- la $a0, __bss_start
- la $a1, _end
-.Lclear_bss:
- sb $0 , 0($a0)
- blt $a0, $a1, .Lclear_bss
- addiu $a0, 1
- la $a0, _end+4 # Initialize heap for malloc (does not use BIOS maalloc)
- li $a1, 1572864 # Allocate 1.5MB at end of bss
- j InitHeap
- nop
- \ No newline at end of file
diff --git a/libpsn00b/libc/malloc.s b/libpsn00b/libc/malloc.s
index 90f9bd4..e441bbe 100644
--- a/libpsn00b/libc/malloc.s
+++ b/libpsn00b/libc/malloc.s
@@ -1,5 +1,10 @@
# Custom first-fit malloc routines by Lameguy64
# Part of the PSn00bSDK Project
+#
+# NOTE: there reportedly is a GCC bug which messes up .weak functions written
+# in assembly if LTO is enabled. I haven't tested but, according to the
+# internet, this bug has never been fixed.
+# https://gcc.gnu.org/legacy-ml/gcc-help/2019-10/msg00092.html
.set noreorder
@@ -10,7 +15,6 @@
.section .text
-
# Stupid small function just to get bss end
# due to GCC insisting externs to be gp relative
.global GetBSSend
@@ -27,6 +31,7 @@ GetBSSend:
#
.global InitHeap
.type InitHeap, @function
+.weak InitHeap
InitHeap:
la $v0, _malloc_addr
sw $a0, 0($v0)
@@ -43,6 +48,7 @@ InitHeap:
# a0 - Size of memory heap in bytes
.global SetHeapSize
.type SetHeapSize, @function
+.weak SetHeapSize
SetHeapSize:
la $v1, _malloc_size
lw $v0, 0($v1)
@@ -55,6 +61,7 @@ SetHeapSize:
#
.global malloc
.type malloc, @function
+.weak malloc
malloc:
addiu $a0, 3 # Round size to a multiple of 4
srl $a0, 2
@@ -170,6 +177,7 @@ malloc:
#
.global calloc
.type calloc, @function
+.weak calloc
calloc:
mult $a0, $a1
addiu $sp, -4
@@ -199,6 +207,7 @@ calloc:
#
.global free
.type free, @function
+.weak free
free:
addiu $a0, -ND_HSIZ
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 <stdio.h>
+/*
+ * PSn00bSDK startup code
+ * (C) 2021 Lameguy64, spicyjpeg - MPL licensed
+ */
+
+#include <sys/types.h>
#include <string.h>
#include <malloc.h>
-#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]();
+}
diff --git a/libpsn00b/psxapi/sys/flushcache.s b/libpsn00b/psxapi/sys/flushcache.s
new file mode 100644
index 0000000..7eeb510
--- /dev/null
+++ b/libpsn00b/psxapi/sys/flushcache.s
@@ -0,0 +1,10 @@
+.set noreorder
+
+.section .text
+
+.global FlushCache
+.type FlushCache, @function
+FlushCache:
+ addiu $t2, $0, 0xa0
+ jr $t2
+ addiu $t1, $0, 0x44
diff --git a/libpsn00b/psxspu/transfer.s b/libpsn00b/psxspu/transfer.s
index 086bb3b..5b62c28 100644
--- a/libpsn00b/psxspu/transfer.s
+++ b/libpsn00b/psxspu/transfer.s
@@ -20,7 +20,8 @@ SpuSetTransferStartAddr:
li $v0, 0x1000 # Check if value is valid
blt $a0, $v0, .Lbad_value
nop
- li $v0, 0xffff
+ lui $v0, 8 # 0x7ffff = (8<<16)-1
+ addiu $v0, -1
bgt $a0, $v0, .Lbad_value
nop