diff --git a/Configuration.mk b/Configuration.mk index fceb776b7..bc69fd106 100644 --- a/Configuration.mk +++ b/Configuration.mk @@ -55,16 +55,7 @@ PACKAGE_NAME ?= $(shell basename "$(shell pwd)") # 2. (Optional) The name to use when creating the output file. # 3. (Optional) The address to use as the fixed start of flash. # 4. (Optional) The address to use as the fixed start of RAM. -# -# By default we currently only build the Cortex-M targets. To enable the RISC-V -# targets, set the RISCV variable like so: -# -# $ make RISCV=1 -# -# Once the RV32 toolchain distribution stabilizes (as of June 2020 the toolchain -# isn't as easily obtained as we would like), we intend to make the RISC-V -# targets build by default as well. -ifeq ($(RISCV),) +ifneq ($(NORISCV),) TOCK_TARGETS ?= cortex-m0 cortex-m3 cortex-m4 cortex-m7 else # Specific addresses useful for the OpenTitan hardware memory map. @@ -286,28 +277,35 @@ override WLFLAGS_rv32imac += $(WLFLAGS_rv32) # Set the system libraries we link against for RISC-V. We support C++ apps by # default. -override LINK_LIBS_rv32 += \ - -lgcc -lstdc++ -lsupc++ +ifeq ($(PICOLIBC),) + override LINK_LIBS_rv32 += -lgcc -lstdc++ -lsupc++ -override LINK_LIBS_rv32i += $(LINK_LIBS_rv32) -override LINK_LIBS_rv32imc += $(LINK_LIBS_rv32) -override LINK_LIBS_rv32imac += $(LINK_LIBS_rv32) + # Use precompiled libaries we provide to link against. + override LEGACY_LIBS_rv32i += \ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libc.a\ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libm.a -# Use precompiled libaries we provide to link against. -override LEGACY_LIBS_rv32i += \ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libc.a\ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32i/libm.a + override LEGACY_LIBS_rv32im += \ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libc.a\ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libm.a -override LEGACY_LIBS_rv32im += \ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libc.a\ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32im/libm.a + override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im) -override LEGACY_LIBS_rv32imc += $(LEGACY_LIBS_rv32im) + override LEGACY_LIBS_rv32imac += \ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libc.a\ + $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libm.a +else + override CFLAGS_rv32i += --specs=picolibc.specs + override CFLAGS_rv32im += --specs=picolibc.specs + override CFLAGS_rv32imc += --specs=picolibc.specs + override CFLAGS_rv32imac += --specs=picolibc.specs -override LEGACY_LIBS_rv32imac += \ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libc.a\ - $(TOCK_USERLAND_BASE_DIR)/newlib/rv32/rv32imac/libm.a + override LINK_LIBS_rv32 += -lgcc -lc -lm +endif +override LINK_LIBS_rv32i += $(LINK_LIBS_rv32) +override LINK_LIBS_rv32imc += $(LINK_LIBS_rv32) +override LINK_LIBS_rv32imac += $(LINK_LIBS_rv32) ################################################################################ ## @@ -442,6 +440,8 @@ override CPPFLAGS += -Wwrite-strings # # { char* c = "foo"; c[0] = 'b override CPPFLAGS_gcc += -Wlogical-op # # "suspicious use of logical operators in expressions" (a lint) override CPPFLAGS_gcc += -Wtrampolines # # attempt to generate a trampoline on the NX stack +override CPPFLAGS_gcc += -Wno-error=sign-compare # Triggers an error inside picolibc + #CPPFLAGS += -Wabi -Wabi-tag # inter-compiler abi issues #CPPFLAGS += -Waggregate-return # warn if things return struct's #CPPFLAGS += -Wcast-align # { char *c; int *i = (int*) c}, 1 byte -> 4 byte align diff --git a/README.md b/README.md index b3cd031e8..37dbe4e07 100644 --- a/README.md +++ b/README.md @@ -33,161 +33,133 @@ Prerequisites $ cd libtock-c ``` -1. The main requirement to build the C applications in this repository is having - cross compilers for embedded targets. You will need an `arm-none-eabi` - toolchain for Cortex-M targets. +1. There are two requirements for building libtock-c applications. - **MacOS**: - ``` - $ brew tap ARMmbed/homebrew-formulae && brew update && brew install arm-none-eabi-gcc - ``` + 1. Cross compiler for embedded targets - **Ubuntu (18.04LTS or later)**: - ``` - $ sudo apt install gcc-arm-none-eabi - ``` + **MacOS**: - **Arch**: - ``` - $ sudo pacman -Syu arm-none-eabi-gcc arm-none-eabi-newlib - ``` + ```shell + $ brew tap ARMmbed/homebrew-formulae && brew update && brew install arm-none-eabi-gcc + $ brew tap riscv/riscv && brew update && brew install riscv-gnu-toolchain + ``` - **Fedora**: - ``` - $ sudo dnf install arm-none-eabi-newlib arm-none-eabi-gcc-cs - ``` + **Ubuntu (21.10 or later) or Debian (11 or later)**: -2. Optional: libtock-c also includes support for building for ***RISC-V - targets***. These are not included by default since obtaining the toolchain - can be difficult (as of July 2022). You will need a RISC-V toolchain that - supports rv32 targets (64 bit toolchains support rv32 if compiled with - multilib support). Some toolchains that can work: + ```shell + $ sudo apt install gcc-arm-none-eabi + $ sudo apt install gcc-riscv64-unknown-elf + ``` - - riscv64-none-elf - - riscv32-none-elf - - riscv64-elf - - riscv64-unknown-elf - - riscv32-unknown-elf + **Arch**: - To actually build for the RISC-V targets, add `RISCV=1` to the make command: + ```shell + $ sudo pacman -Syu arm-none-eabi-gcc + $ sudo pacman -Syu riscv64-elf-gcc + ``` - $ make RISCV=1 + **Fedora**: - **MacOS**: - ``` - $ brew tap riscv/riscv && brew update && brew install riscv-gnu-toolchain - ``` + NOTE: Fedora currently doesn't have RISC-V support - **Ubuntu (21.10 or later)**: - ``` - $ sudo apt install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf - ``` + ```shell + $ sudo dnf install arm-none-eabi-gcc-cs + ``` - **Ubuntu (21.04 or earlier)**: + **Other distros**: - Unfortunately, older Ubuntu does not provide a package for RISC-V libc. We - have created a .deb file you can use to install a suitable libc based on - newlib: - ``` - $ wget http://cs.virginia.edu/~bjc8c/archive/newlib_3.3.0-1_amd64.deb - $ sudo dpkg -i newlib_3.3.0-1_amd64.deb - ``` + If your distro doesn't provide a RISC-V toolchain you can build one yourself + or just disable RISC-V support by running - If you would rather compile your own newlib-based libc, follow the steps - below. Section [newlib-nano](newlib-nano) describes some extra config options - to build a size optimised newlib. - ``` - # Download newlib 3.3 from https://sourceware.org/newlib/ - $ wget ftp://sourceware.org/pub/newlib/newlib-3.3.0.tar.gz - $ tar -xvf newlib-3.3.0.tar.gz - $ cd newlib-3.3.0 - # Disable stdlib for building - $ export CFLAGS=-nostdlib - # Run configure - $ ./configure --disable-newlib-supplied-syscalls --with-gnu-ld --with-newlib --enable-languages=c --target=riscv64-unknown-elf --host=x86 --disable-multi-lib --prefix /usr - # Build and then install - $ make -j8 - $ sudo make install - ``` - - Alternatively, you may use a pre-compiled toolchain that we created with - Crosstool-NG. - ``` - $ wget http://cs.virginia.edu/~bjc8c/archive/gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip - $ unzip gcc-riscv64-unknown-elf-8.3.0-ubuntu.zip - # add gcc-riscv64-unknown-elf-8.3.0-ubuntu/bin to your `$PATH` variable. - ``` + ```shell + NORISCV=1 make + ``` - **Arch**: - ``` - $ sudo pacman -Syu riscv64-elf-gcc riscv32-elf-newlib arm-none-eabi-newlib riscv64-elf-newlib - ``` + 1. libc for embedded targets - **Fedora**: + **Ubuntu (21.10 or later) or Debian (11 or later)**: - **dnf** does not contain the `riscv-gnu-toolchain`, an alternative is to - compile from source. Start with some of the tools we need to compile the - source. - ``` - $ sudo dnf install make automake gcc gcc-c++ kernel-devel texinfo expat expat-devel - $ sudo dnf group install "Development Tools" "C Development Tools and Libraries" - ``` - Get `riscv-gnu-toolchain`, [summarised instructions as stated - here](https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/README.md) - ``` - $ git clone https://github.com/riscv/riscv-gnu-toolchain - $ cd riscv-gnu-toolchain/ - ``` - **Note: add /opt/riscv/bin to your PATH**, then, - ``` - $ ./configure --prefix=/opt/riscv --enable-multilib - ``` - `--enable-multilib` ensures that "the multilib compiler will have the prefix - riscv64-unknown-elf- or riscv64-unknown-linux-gnu- but will be able to target - both 32-bit and 64-bit systems." - ``` - $ sudo make [might need elevated privileges writing to `/opt/`] - ``` - additionally, with - ``` - $ sudo make linux - ``` - you can also build `riscv64-unknown-linux-gnu`, which can be useful with tock - where `riscv64-unknown-linux-gnu-objcopy` is used. + Use picolibc instead of newlib - After the the source has been compiled and copied to `/opt/riscv` and - `/opt/riscv/bin`has appended to the PATH, the toolchain is ready to be used. + ```shell + $ sudo apt install picolibc-riscv64-unknown-elf + ``` + **Arch**: - **newlib-nano**: + ```shell + $ sudo pacman -Syu riscv32-elf-newlib + ``` - newlib can require a large amount of memory, especially for printing. - If this is a concern you can instead use a more size optimised version. - As of August 2020 there are a few options for this. + **Fedora**: - - See if the version of newlib from your distro already has the flags below - enabled. If it does it's already size optimsed. - - See if your distro pacakges a newlib-nano (Debian does this) that will - already include the flags below. - - See if your distro packages picolibc, which is a optimised fork of newlib. - - You can compile newlib with these extra flags: + ```shell + $ sudo dnf install arm-none-eabi-newlib ``` - --enable-newlib-reent-small \ - --disable-newlib-fvwrite-in-streamio \ - --disable-newlib-fseek-optimization \ - --disable-newlib-wide-orient \ - --enable-newlib-nano-malloc \ - --disable-newlib-unbuf-stream-opt \ - --enable-lite-exit \ - --enable-newlib-global-atexit \ - --enable-newlib-nano-formatted-io + + *newlib-nano* + + newlib can require a large amount of memory, especially for printing. + If this is a concern you can instead use a more size optimised version. + As of August 2020 there are a few options for this. + + - See if the version of newlib from your distro already has the flags below + enabled. If it does it's already size optimsed. + - See if your distro packages picolibc, which is a optimised fork of newlib. + - You can compile newlib with these extra flags: + ```shell + --enable-newlib-reent-small \ + --disable-newlib-fvwrite-in-streamio \ + --disable-newlib-fseek-optimization \ + --disable-newlib-wide-orient \ + --enable-newlib-nano-malloc \ + --disable-newlib-unbuf-stream-opt \ + --enable-lite-exit \ + --enable-newlib-global-atexit \ + --enable-newlib-nano-formatted-io + ``` + + If you would rather compile your own newlib-based libc, follow the steps + below. + + ```shell + # Download newlib 4.1 from https://sourceware.org/newlib/ + $ wget ftp://sourceware.org/pub/newlib/newlib-4.1.0.tar.gz + $ tar -xvf newlib-4.1.0.tar.gz + $ cd newlib-4.1.0 + # Disable stdlib for building + $ export CFLAGS=-nostdlib + # Run configure + $ ./configure --disable-newlib-supplied-syscalls --with-gnu-ld --with-newlib --enable-languages=c --target=riscv64-unknown-elf --host=x86 --disable-multi-lib --prefix /usr + # Build and then install + $ make -j8 + $ sudo make install ``` -3. Optional: libtock-c also includes support for building RISC-V targets with +1. Optional: Newlib is a commonly used embedded libc. Although it does have a + few limitations. Mostly in that the print implementation can be + (too large)[https://keithp.com/picolibc/picolibc-2021-notes.pdf] and the + license can be (too restrictive)[https://github.com/tock/libtock-c/issues/309]. + Newlib for RISC-V also isn't pre-packaged for Debian systems. + + If you would prefer to use picolibc instead of newlib for RISC-V you can + follow this step. If you are happy using newlib or aren't building for + RISC-V you can skip this step. picolibc isn't support on ARM platforms + at the moment. + + If using picolibc then specify the `PICOLIBC` variable. + + ```shell + $ make PICOLIBC=1 + ``` + +1. Optional: libtock-c also includes support for building RISC-V targets with the LLVM clang compiler. If you have a compatible clang toolchain, you can add `CLANG=1` to the make command to use clang instead of the default GCC. - $ make RISCV=1 CLANG=1 + ```shell + $ make CLANG=1 + ``` This support is only included for RISC-V targets as Cortex-M targets require the FDPIC support only present in GCC. diff --git a/libtock/console.c b/libtock/console.c index 7d69f21ec..9fbb8e897 100644 --- a/libtock/console.c +++ b/libtock/console.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -150,3 +151,34 @@ int getnstr_abort(void) { syscall_return_t com = command(DRIVER_NUM_CONSOLE, 3, 0, 0); return tock_command_return_novalue_to_returncode(com); } + +/* + * If running with picolibc let's deine the `__iob` array. + * This is used for stdin/stdout/stderr + * https://github.com/picolibc/picolibc/blob/main/doc/os.md#stdinstdoutstderr + */ +#ifdef _FDEV_SETUP_RW + +static int picolibc_putc(char c, FILE *file) +{ + (void) file; /* Not used in this function */ + putnstr(&c, 1); /* Defined by underlying system */ + return c; +} + +static int picolibc_getc(FILE *file) +{ + unsigned char c; + (void) file; /* Not used in this function */ + c = getch(); /* Defined by underlying system */ + return c; +} + +static FILE __stdio = FDEV_SETUP_STREAM(picolibc_putc, + picolibc_getc, + NULL, + _FDEV_SETUP_RW); + +FILE *const __iob[3] = { &__stdio, &__stdio, &__stdio }; + +#endif diff --git a/libtock/udp.h b/libtock/udp.h index ad0e6aa37..3c20b4a98 100644 --- a/libtock/udp.h +++ b/libtock/udp.h @@ -4,6 +4,7 @@ #include #include "tock.h" +#include #ifdef __cplusplus extern "C" { diff --git a/userland_generic.ld b/userland_generic.ld index 3056ef659..627027b2a 100644 --- a/userland_generic.ld +++ b/userland_generic.ld @@ -161,6 +161,9 @@ SECTIONS { KEEP(*(.sbss*)) /* for RISC-V */ *(COMMON) . = ALIGN(4); + __heap_start = .; + . = __heap_start + APP_HEAP_SIZE; + __heap_end = .; } > SRAM /* End of flash. */