Skip to content

Commit a166170

Browse files
committed
asset, kernel, toolchain: initial picolibc support
1 parent ccfa43b commit a166170

7 files changed

Lines changed: 168 additions & 40 deletions

File tree

src/asset.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,13 @@ static fpos_t seekfn_none(void *c, fpos_t pos, int whence)
275275
return -1;
276276
}
277277

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

308+
#if defined(__PICOLIBC__) && defined(TINY_STDIO)
309+
static int readfn_cmp(void *c, void *buf, size_t sz)
310+
#elif defined(__PICOLIBC__)
311+
static int readfn_cmp(void *c, char *buf, size_t sz)
312+
#else
302313
static int readfn_cmp(void *c, char *buf, int sz)
314+
#endif
303315
{
304316
cookie_cmp_t *cookie = (cookie_cmp_t*)c;
305317
assertf(!cookie->seeked, "Cannot seek in file opened via asset_fopen (it might be compressed)");

src/kernel/kernel.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ reg_block_t* __kthread_syscall_schedule(reg_block_t *stack_state)
326326

327327
th_cur_tp = th_cur->tp_value;
328328

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

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

386-
#ifdef __NEWLIB__
386+
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
387387
th_main.tls.reent_ptr = _REENT;
388388
#endif
389389

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

452452
int extra_size = TLS_SIZE;
453-
#ifdef __NEWLIB__
453+
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
454454
extra_size += sizeof(struct _reent);
455455
#endif
456456
void *thmem = malloc(STACK_GUARD + stack_size + sizeof(kthread_t) + extra_size);
@@ -516,7 +516,7 @@ kthread_t* __kthread_new_internal(const char *name, int stack_size, int8_t pri,
516516
th->tp_value = extra+TP_OFFSET;
517517
extra += TLS_SIZE;
518518
// TLS initial configuration
519-
#ifdef __NEWLIB__
519+
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
520520
th->tls.reent_ptr = extra;
521521
_REENT_INIT_PTR(th->tls.reent_ptr);
522522
#endif

src/kernel/kernel_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#define __LIBDRAGON_KERNEL_INTERNAL_H
88

99
#include "kernel.h"
10-
#ifdef __NEWLIB__
10+
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
1111
#include <sys/reent.h>
1212
#endif
1313

@@ -57,7 +57,7 @@ typedef struct __attribute__((aligned (8))) kthread_s
5757
int interrupt_depth;
5858
/** Mirror of __interrupt_sr */
5959
int interrupt_sr;
60-
#ifdef __NEWLIB__
60+
#if defined(__NEWLIB__) && !defined(__PICOLIBC__)
6161
/** Newlib reentrancy */
6262
struct _reent *reent_ptr;
6363
#endif

src/system.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <fcntl.h>
1111
#include <sys/types.h>
1212
#include <sys/stat.h>
13+
#include <sys/time.h>
1314
#include <sys/times.h>
1415
#include <stdarg.h>
1516
#include <stdint.h>
@@ -35,6 +36,13 @@
3536
#define STDERR_FILENO 2
3637
/** @} */
3738

39+
#if defined(__PICOLIBC__) && defined(TINY_STDIO)
40+
/* Force weakly referenced default stdin/stdout/stderr implementations to be linked. */
41+
__asm__(".equ stdin_reference, stdin");
42+
__asm__(".equ stdout_reference, stdout");
43+
__asm__(".equ stderr_reference, stderr");
44+
#endif
45+
3846
/**
3947
* @brief Stack size
4048
*

src/system_newlib_locks.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
#include "kernel.h"
1414
#include <stdio.h>
15+
#include <sys/lock.h>
1516

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

119120
///@endcond
120121

121-
#endif
122+
#endif

tools/build-toolchain.sh

Lines changed: 120 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ N64_BUILD=${N64_BUILD:-""}
2222
N64_HOST=${N64_HOST:-""}
2323
N64_TARGET=${N64_TARGET:-mips64-elf}
2424

25+
# Toolchain configuration options.
26+
N64_USE_PICOLIBC=${N64_USE_PICOLIBC:-"false"}
27+
N64_USE_PICOLIBC_TINYSTDIO=${N64_USE_PICOLIBC_TINYSTDIO:-"false"}
28+
N64_USE_PICOLIBC_LEGACY_STDIO=true
29+
if [ "$N64_USE_PICOLIBC_TINYSTDIO" == "true" ]; then
30+
N64_USE_PICOLIBC_LEGACY_STDIO=false
31+
fi
32+
2533
# Set N64_INST before calling the script to change the default installation directory path
2634
INSTALL_PATH="${N64_INST}"
2735
# Set PATH for newlib to compile using GCC for MIPS N64 (pass 1)
@@ -38,8 +46,9 @@ GCC_CONFIGURE_ARGS=()
3846
BINUTILS_V=2.43.1
3947
GCC_V=14.2.0
4048
NEWLIB_V=4.4.0.20231231
41-
GMP_V=6.3.0
42-
MPC_V=1.3.1
49+
PICOLIBC_V=e0a04fec075f5cb1ddb80ea8c359748ef72b9122
50+
GMP_V=6.3.0
51+
MPC_V=1.3.1
4352
MPFR_V=4.2.1
4453
MAKE_V=${MAKE_V:-""}
4554

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

107-
test -f "newlib-$NEWLIB_V.tar.gz" || download "https://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz"
108-
test -d "newlib-$NEWLIB_V" || tar -xzf "newlib-$NEWLIB_V.tar.gz"
116+
if [ "$N64_USE_PICOLIBC" == "true" ]; then
117+
test -f "picolibc-$PICOLIBC_V.zip" || ( download "https://github.com/picolibc/picolibc/archive/$PICOLIBC_V.zip" && mv "$PICOLIBC_V.zip" "picolibc-$PICOLIBC_V.zip" )
118+
test -d "picolibc-$PICOLIBC_V" || unzip "picolibc-$PICOLIBC_V.zip"
119+
else
120+
test -f "newlib-$NEWLIB_V.tar.gz" || download "https://sourceware.org/pub/newlib/newlib-$NEWLIB_V.tar.gz"
121+
test -d "newlib-$NEWLIB_V" || tar -xzf "newlib-$NEWLIB_V.tar.gz"
122+
fi
109123

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

223-
# Compile newlib for target.
224-
mkdir -p newlib_compile_target
225-
pushd newlib_compile_target
226-
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
227-
--prefix="$CROSS_PREFIX" \
228-
--target="$N64_TARGET" \
229-
--with-cpu=mips64vr4300 \
230-
--disable-libssp \
231-
--disable-werror \
232-
--enable-newlib-multithread \
233-
--enable-newlib-retargetable-locking
234-
make -j "$JOBS"
235-
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
236-
popd
237+
if [ "$N64_USE_PICOLIBC" == "true" ]; then
238+
# Compile picolibc for target.
239+
mkdir -p picolibc_compile_target
240+
pushd picolibc_compile_target
241+
meson setup \
242+
--cross-file=../../meson-cross.txt \
243+
-Dmultilib=false \
244+
-Dpicocrt=false \
245+
-Dpicolib=false \
246+
-Dsemihost=false \
247+
-Dspecsdir=none \
248+
-Dtests=false \
249+
-Dtinystdio="$N64_USE_PICOLIBC_TINYSTDIO" \
250+
-Dfast-bufio=true \
251+
-Dio-long-long=true \
252+
-Dio-pos-args="$N64_USE_PICOLIBC_TINYSTDIO" \
253+
-Dio-percent-b=true \
254+
-Dposix-console=true \
255+
-Dformat-default=double \
256+
-Dnewlib-fseek-optimization="$N64_USE_PICOLIBC_LEGACY_STDIO" \
257+
-Dnewlib-fvwrite-in-streamio="$N64_USE_PICOLIBC_LEGACY_STDIO" \
258+
-Dnewlib-io-float="$N64_USE_PICOLIBC_LEGACY_STDIO" \
259+
-Dnewlib-stdio64=false \
260+
-Dnewlib-unbuf-stream-opt="$N64_USE_PICOLIBC_LEGACY_STDIO" \
261+
-Dnewlib-nano-malloc=false \
262+
-Dnewlib-multithread=true \
263+
-Dnewlib-retargetable-locking=true \
264+
-Dthread-local-storage=true \
265+
-Dprefix="$CROSS_PREFIX" \
266+
-Dlibdir=mips64-elf/lib \
267+
-Dincludedir=mips64-elf/include \
268+
../"picolibc-$PICOLIBC_V"
269+
ninja -j "$JOBS"
270+
ninja install || sudo env PATH="$PATH" ninja install || su -c "env PATH=\"$PATH\" ninja install"
271+
popd
272+
else
273+
# Compile newlib for target.
274+
mkdir -p newlib_compile_target
275+
pushd newlib_compile_target
276+
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
277+
--prefix="$CROSS_PREFIX" \
278+
--target="$N64_TARGET" \
279+
--with-cpu=mips64vr4300 \
280+
--disable-libssp \
281+
--disable-werror \
282+
--enable-newlib-multithread \
283+
--enable-newlib-retargetable-locking
284+
make -j "$JOBS"
285+
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
286+
popd
287+
fi
237288

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

289-
# Compile newlib for target.
290-
mkdir -p newlib_compile
291-
pushd newlib_compile
292-
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
293-
--prefix="$INSTALL_PATH" \
294-
--target="$N64_TARGET" \
295-
--with-cpu=mips64vr4300 \
296-
--disable-libssp \
297-
--disable-werror \
298-
--enable-newlib-multithread \
299-
--enable-newlib-retargetable-locking
300-
make -j "$JOBS"
301-
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
302-
popd
340+
if [ "$N64_USE_PICOLIBC" == "true" ]; then
341+
# Compile picolibc for target.
342+
mkdir -p picolibc_compile_target
343+
pushd picolibc_compile_target
344+
meson setup \
345+
--cross-file=../../meson-cross.txt \
346+
-Dmultilib=false \
347+
-Dpicocrt=false \
348+
-Dpicolib=false \
349+
-Dsemihost=false \
350+
-Dspecsdir=none \
351+
-Dtests=false \
352+
-Dtinystdio="$N64_USE_PICOLIBC_TINYSTDIO" \
353+
-Dfast-bufio=true \
354+
-Dio-long-long=true \
355+
-Dio-pos-args="$N64_USE_PICOLIBC_TINYSTDIO" \
356+
-Dio-percent-b=true \
357+
-Dposix-console=true \
358+
-Dformat-default=double \
359+
-Dnewlib-fseek-optimization="$N64_USE_PICOLIBC_LEGACY_STDIO" \
360+
-Dnewlib-fvwrite-in-streamio="$N64_USE_PICOLIBC_LEGACY_STDIO" \
361+
-Dnewlib-io-float="$N64_USE_PICOLIBC_LEGACY_STDIO" \
362+
-Dnewlib-stdio64=false \
363+
-Dnewlib-unbuf-stream-opt="$N64_USE_PICOLIBC_LEGACY_STDIO" \
364+
-Dnewlib-nano-malloc=false \
365+
-Dnewlib-multithread=true \
366+
-Dnewlib-retargetable-locking=true \
367+
-Dthread-local-storage=false \
368+
-Dprefix="$INSTALL_PATH" \
369+
-Dlibdir=mips64-elf/lib \
370+
-Dincludedir=mips64-elf/include \
371+
../"picolibc-$PICOLIBC_V"
372+
ninja -j "$JOBS"
373+
ninja install || sudo env PATH="$PATH" ninja install || su -c "env PATH=\"$PATH\" ninja install"
374+
popd
375+
else
376+
# Compile newlib for target.
377+
mkdir -p newlib_compile_target
378+
pushd newlib_compile_target
379+
CFLAGS_FOR_TARGET="-DHAVE_ASSERT_FUNC -O2 -fpermissive" ../"newlib-$NEWLIB_V"/configure \
380+
--prefix="$INSTALL_PATH" \
381+
--target="$N64_TARGET" \
382+
--with-cpu=mips64vr4300 \
383+
--disable-libssp \
384+
--disable-werror \
385+
--enable-newlib-multithread \
386+
--enable-newlib-retargetable-locking
387+
make -j "$JOBS"
388+
make install || sudo env PATH="$PATH" make install || su -c "env PATH=\"$PATH\" make install"
389+
popd
390+
fi
303391

304392
# Finish compiling GCC
305393
mkdir -p gcc_compile

tools/meson-cross.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[binaries]
2+
# Meson 0.53.2 doesn't use any cflags when doing basic compiler tests,
3+
# so we have to add -nostdlib to the compiler configuration itself or
4+
# early compiler tests will fail. This can be removed when picolibc
5+
# requires at least version 0.54.2 of meson.
6+
c = ['mips64-elf-gcc', '-nostdlib']
7+
ar = 'mips64-elf-ar'
8+
as = 'mips64-elf-as'
9+
nm = 'mips64-elf-nm'
10+
strip = 'mips64-elf-strip'
11+
12+
[host_machine]
13+
system = 'none'
14+
cpu_family = 'mips64'
15+
cpu = 'mips64vr4300'
16+
endian = 'big'
17+
18+
[properties]
19+
skip_sanity_check = true

0 commit comments

Comments
 (0)