Skip to content

Commit

Permalink
asset, kernel, toolchain: initial picolibc support
Browse files Browse the repository at this point in the history
  • Loading branch information
asiekierka committed Nov 29, 2024
1 parent ccfa43b commit a166170
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 40 deletions.
12 changes: 12 additions & 0 deletions src/asset.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,13 @@ static fpos_t seekfn_none(void *c, fpos_t pos, int whence)
return -1;
}

#if defined(__PICOLIBC__) && defined(TINY_STDIO)
static int readfn_none(void *c, void *buf, size_t sz)
#elif defined(__PICOLIBC__)
static int readfn_none(void *c, char *buf, size_t sz)
#else
static int readfn_none(void *c, char *buf, int sz)
#endif
{
cookie_none_t *cookie = c;
assertf(!cookie->seeked, "Cannot seek in file opened via asset_fopen (it might be compressed)");
Expand All @@ -299,7 +305,13 @@ typedef struct {
uint8_t alignas(8) state[];
} cookie_cmp_t;

#if defined(__PICOLIBC__) && defined(TINY_STDIO)
static int readfn_cmp(void *c, void *buf, size_t sz)
#elif defined(__PICOLIBC__)
static int readfn_cmp(void *c, char *buf, size_t sz)
#else
static int readfn_cmp(void *c, char *buf, int sz)
#endif
{
cookie_cmp_t *cookie = (cookie_cmp_t*)c;
assertf(!cookie->seeked, "Cannot seek in file opened via asset_fopen (it might be compressed)");
Expand Down
10 changes: 5 additions & 5 deletions src/kernel/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ reg_block_t* __kthread_syscall_schedule(reg_block_t *stack_state)

th_cur_tp = th_cur->tp_value;

#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
_REENT = th_cur->tls.reent_ptr;
#endif

Expand Down Expand Up @@ -356,7 +356,7 @@ kthread_t* kernel_init(void)
{
assertf(__tdata_align <= 8, "Unsupported TLS alignment of %d (Maximum 8)", __tdata_align);
assert(!__kernel);
#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
// Check if __malloc_lock is a nop. This happens with old toolchains where
// newlib was compiled with --disable-threads.
extern void __malloc_lock(void);
Expand All @@ -383,7 +383,7 @@ kthread_t* kernel_init(void)
th_main.flags = TH_FLAG_DETACHED; // main thread cannot be joined
th_main.tp_value = __tls_base+TP_OFFSET;

#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
th_main.tls.reent_ptr = _REENT;
#endif

Expand Down Expand Up @@ -450,7 +450,7 @@ kthread_t* __kthread_new_internal(const char *name, int stack_size, int8_t pri,
// make debugging more difficult and might even cause the kernel to crash.

int extra_size = TLS_SIZE;
#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
extra_size += sizeof(struct _reent);
#endif
void *thmem = malloc(STACK_GUARD + stack_size + sizeof(kthread_t) + extra_size);
Expand Down Expand Up @@ -516,7 +516,7 @@ kthread_t* __kthread_new_internal(const char *name, int stack_size, int8_t pri,
th->tp_value = extra+TP_OFFSET;
extra += TLS_SIZE;
// TLS initial configuration
#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
th->tls.reent_ptr = extra;
_REENT_INIT_PTR(th->tls.reent_ptr);
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/kernel/kernel_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define __LIBDRAGON_KERNEL_INTERNAL_H

#include "kernel.h"
#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
#include <sys/reent.h>
#endif

Expand Down Expand Up @@ -57,7 +57,7 @@ typedef struct __attribute__((aligned (8))) kthread_s
int interrupt_depth;
/** Mirror of __interrupt_sr */
int interrupt_sr;
#ifdef __NEWLIB__
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
/** Newlib reentrancy */
struct _reent *reent_ptr;
#endif
Expand Down
8 changes: 8 additions & 0 deletions src/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/times.h>
#include <stdarg.h>
#include <stdint.h>
Expand All @@ -35,6 +36,13 @@
#define STDERR_FILENO 2
/** @} */

#if defined(__PICOLIBC__) && defined(TINY_STDIO)
/* Force weakly referenced default stdin/stdout/stderr implementations to be linked. */
__asm__(".equ stdin_reference, stdin");
__asm__(".equ stdout_reference, stdout");
__asm__(".equ stderr_reference, stderr");
#endif

/**
* @brief Stack size
*
Expand Down
3 changes: 2 additions & 1 deletion src/system_newlib_locks.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
#include "kernel.h"
#include <stdio.h>
#include <sys/lock.h>

// Toolchains since Sept 2024 build with threads and retargetable locks enabled,
// both of which are required for libc to be thread safe and thus the kernel
Expand Down Expand Up @@ -118,4 +119,4 @@ void __retarget_lock_release_recursive (_LOCK_T lock) {

///@endcond

#endif
#endif
152 changes: 120 additions & 32 deletions tools/build-toolchain.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ N64_BUILD=${N64_BUILD:-""}
N64_HOST=${N64_HOST:-""}
N64_TARGET=${N64_TARGET:-mips64-elf}

# Toolchain configuration options.
N64_USE_PICOLIBC=${N64_USE_PICOLIBC:-"false"}
N64_USE_PICOLIBC_TINYSTDIO=${N64_USE_PICOLIBC_TINYSTDIO:-"false"}
N64_USE_PICOLIBC_LEGACY_STDIO=true
if [ "$N64_USE_PICOLIBC_TINYSTDIO" == "true" ]; then
N64_USE_PICOLIBC_LEGACY_STDIO=false
fi

# Set N64_INST before calling the script to change the default installation directory path
INSTALL_PATH="${N64_INST}"
# Set PATH for newlib to compile using GCC for MIPS N64 (pass 1)
Expand All @@ -38,8 +46,9 @@ GCC_CONFIGURE_ARGS=()
BINUTILS_V=2.43.1
GCC_V=14.2.0
NEWLIB_V=4.4.0.20231231
GMP_V=6.3.0
MPC_V=1.3.1
PICOLIBC_V=e0a04fec075f5cb1ddb80ea8c359748ef72b9122
GMP_V=6.3.0
MPC_V=1.3.1
MPFR_V=4.2.1
MAKE_V=${MAKE_V:-""}

Expand Down Expand Up @@ -104,8 +113,13 @@ test -d "binutils-$BINUTILS_V" || tar -xzf "binutils-$BINUTILS_V.tar.gz"
test -f "gcc-$GCC_V.tar.gz" || download "https://ftp.gnu.org/gnu/gcc/gcc-$GCC_V/gcc-$GCC_V.tar.gz"
test -d "gcc-$GCC_V" || tar -xzf "gcc-$GCC_V.tar.gz"

test -f "newlib-$NEWLIB_V.tar.gz" || download "https://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz"
test -d "newlib-$NEWLIB_V" || tar -xzf "newlib-$NEWLIB_V.tar.gz"
if [ "$N64_USE_PICOLIBC" == "true" ]; then
test -f "picolibc-$PICOLIBC_V.zip" || ( download "https://github.com/picolibc/picolibc/archive/$PICOLIBC_V.zip" && mv "$PICOLIBC_V.zip" "picolibc-$PICOLIBC_V.zip" )
test -d "picolibc-$PICOLIBC_V" || unzip "picolibc-$PICOLIBC_V.zip"
else
test -f "newlib-$NEWLIB_V.tar.gz" || download "https://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz"
test -d "newlib-$NEWLIB_V" || tar -xzf "newlib-$NEWLIB_V.tar.gz"
fi

if [ "$GMP_V" != "" ]; then
test -f "gmp-$GMP_V.tar.bz2" || download "https://ftp.gnu.org/gnu/gmp/gmp-$GMP_V.tar.bz2"
Expand Down Expand Up @@ -220,20 +234,57 @@ make all-target-libgcc -j "$JOBS"
make install-target-libgcc || sudo make install-target-libgcc || su -c "make install-target-libgcc"
popd

# Compile newlib for target.
mkdir -p newlib_compile_target
pushd newlib_compile_target
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
--prefix="$CROSS_PREFIX" \
--target="$N64_TARGET" \
--with-cpu=mips64vr4300 \
--disable-libssp \
--disable-werror \
--enable-newlib-multithread \
--enable-newlib-retargetable-locking
make -j "$JOBS"
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
popd
if [ "$N64_USE_PICOLIBC" == "true" ]; then
# Compile picolibc for target.
mkdir -p picolibc_compile_target
pushd picolibc_compile_target
meson setup \
--cross-file=../../meson-cross.txt \
-Dmultilib=false \
-Dpicocrt=false \
-Dpicolib=false \
-Dsemihost=false \
-Dspecsdir=none \
-Dtests=false \
-Dtinystdio="$N64_USE_PICOLIBC_TINYSTDIO" \
-Dfast-bufio=true \
-Dio-long-long=true \
-Dio-pos-args="$N64_USE_PICOLIBC_TINYSTDIO" \
-Dio-percent-b=true \
-Dposix-console=true \
-Dformat-default=double \
-Dnewlib-fseek-optimization="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-fvwrite-in-streamio="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-io-float="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-stdio64=false \
-Dnewlib-unbuf-stream-opt="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-nano-malloc=false \
-Dnewlib-multithread=true \
-Dnewlib-retargetable-locking=true \
-Dthread-local-storage=true \
-Dprefix="$CROSS_PREFIX" \
-Dlibdir=mips64-elf/lib \
-Dincludedir=mips64-elf/include \
../"picolibc-$PICOLIBC_V"
ninja -j "$JOBS"
ninja install || sudo env PATH="$PATH" ninja install || su -c "env PATH=\"$PATH\" ninja install"
popd
else
# Compile newlib for target.
mkdir -p newlib_compile_target
pushd newlib_compile_target
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
--prefix="$CROSS_PREFIX" \
--target="$N64_TARGET" \
--with-cpu=mips64vr4300 \
--disable-libssp \
--disable-werror \
--enable-newlib-multithread \
--enable-newlib-retargetable-locking
make -j "$JOBS"
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
popd
fi

# For a standard cross-compiler, the only thing left is to finish compiling the target libraries
# like libstd++. We can continue on the previous GCC build target.
Expand Down Expand Up @@ -286,20 +337,57 @@ else
make install-target-libgcc || sudo make install-target-libgcc || su -c "make install-target-libgcc"
popd

# Compile newlib for target.
mkdir -p newlib_compile
pushd newlib_compile
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
--prefix="$INSTALL_PATH" \
--target="$N64_TARGET" \
--with-cpu=mips64vr4300 \
--disable-libssp \
--disable-werror \
--enable-newlib-multithread \
--enable-newlib-retargetable-locking
make -j "$JOBS"
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
popd
if [ "$N64_USE_PICOLIBC" == "true" ]; then
# Compile picolibc for target.
mkdir -p picolibc_compile_target
pushd picolibc_compile_target
meson setup \
--cross-file=../../meson-cross.txt \
-Dmultilib=false \
-Dpicocrt=false \
-Dpicolib=false \
-Dsemihost=false \
-Dspecsdir=none \
-Dtests=false \
-Dtinystdio="$N64_USE_PICOLIBC_TINYSTDIO" \
-Dfast-bufio=true \
-Dio-long-long=true \
-Dio-pos-args="$N64_USE_PICOLIBC_TINYSTDIO" \
-Dio-percent-b=true \
-Dposix-console=true \
-Dformat-default=double \
-Dnewlib-fseek-optimization="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-fvwrite-in-streamio="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-io-float="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-stdio64=false \
-Dnewlib-unbuf-stream-opt="$N64_USE_PICOLIBC_LEGACY_STDIO" \
-Dnewlib-nano-malloc=false \
-Dnewlib-multithread=true \
-Dnewlib-retargetable-locking=true \
-Dthread-local-storage=false \
-Dprefix="$INSTALL_PATH" \
-Dlibdir=mips64-elf/lib \
-Dincludedir=mips64-elf/include \
../"picolibc-$PICOLIBC_V"
ninja -j "$JOBS"
ninja install || sudo env PATH="$PATH" ninja install || su -c "env PATH=\"$PATH\" ninja install"
popd
else
# Compile newlib for target.
mkdir -p newlib_compile_target
pushd newlib_compile_target
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
--prefix="$INSTALL_PATH" \
--target="$N64_TARGET" \
--with-cpu=mips64vr4300 \
--disable-libssp \
--disable-werror \
--enable-newlib-multithread \
--enable-newlib-retargetable-locking
make -j "$JOBS"
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
popd
fi

# Finish compiling GCC
mkdir -p gcc_compile
Expand Down
19 changes: 19 additions & 0 deletions tools/meson-cross.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[binaries]
# Meson 0.53.2 doesn't use any cflags when doing basic compiler tests,
# so we have to add -nostdlib to the compiler configuration itself or
# early compiler tests will fail. This can be removed when picolibc
# requires at least version 0.54.2 of meson.
c = ['mips64-elf-gcc', '-nostdlib']
ar = 'mips64-elf-ar'
as = 'mips64-elf-as'
nm = 'mips64-elf-nm'
strip = 'mips64-elf-strip'

[host_machine]
system = 'none'
cpu_family = 'mips64'
cpu = 'mips64vr4300'
endian = 'big'

[properties]
skip_sanity_check = true

0 comments on commit a166170

Please sign in to comment.