diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4d7f3de5..519f82ffd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,3 +51,5 @@ jobs: run: pushd examples; ./build_all.sh || exit; popd - name: ci-debug-build run: pushd examples/blink; make debug RAM_START=0x20004000 FLASH_INIT=0x30051 || exit; popd + - name: ci-build-picolib + run: pushd examples/tests/hello_loop; make clean; make PICOLIB=1 || exit; popd diff --git a/Configuration.mk b/Configuration.mk index f7408f70e..a0709f1ea 100644 --- a/Configuration.mk +++ b/Configuration.mk @@ -197,6 +197,12 @@ override CPPFLAGS_PIC += \ -Wl,--emit-relocs\ -fPIC +ifneq ($(PICOLIB),) + # Use picolib for libc. We need to include the `picolib-tock` library which + # maps Tock's system-level functions to the names that picolib expects. + EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/picolib-tock +endif + ################################################################################ ## ## RISC-V compiler/linker flags @@ -256,10 +262,19 @@ else ifeq ($(CC_rv32_version_major),13) else NEWLIB_VERSION_rv32 := 4.3.0.20230120 endif -NEWLIB_VERSION_rv32i := $(NEWLIB_VERSION_rv32) -NEWLIB_VERSION_rv32imc := $(NEWLIB_VERSION_rv32) -NEWLIB_VERSION_rv32imac := $(NEWLIB_VERSION_rv32) -NEWLIB_BASE_DIR_rv32 := $(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-$(NEWLIB_VERSION_rv32) + +ifeq ($(PICOLIB),) + # Use newlib + TOCK_LIBC_FOLDER_rv32 := libtock-newlib-$(NEWLIB_VERSION_rv32) +else + # Use picolib + TOCK_LIBC_FOLDER_rv32 := libtock-picolib-1.8.5 +endif + +TOCK_LIBC_FOLDER_rv32i := $(TOCK_LIBC_FOLDER_rv32) +TOCK_LIBC_FOLDER_rv32imc := $(TOCK_LIBC_FOLDER_rv32) +TOCK_LIBC_FOLDER_rv32imac := $(TOCK_LIBC_FOLDER_rv32) +TOCK_LIBC_BASE_DIR_rv32 := $(TOCK_USERLAND_BASE_DIR)/lib/$(TOCK_LIBC_FOLDER_rv32) # Match compiler version to supported libtock-libc++ versions. ifeq ($(CC_rv32_version_major),10) @@ -299,7 +314,7 @@ override CFLAGS_rv32imac += $(CFLAGS_rv32) # Set the base `CPPFLAGS` for all RISC-V variants based on the toolchain family. override CPPFLAGS_rv32 += \ $(CPPFLAGS_toolchain_rv32) \ - -isystem $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include \ + -isystem $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include \ -isystem $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include/c++/$(LIBCPP_VERSION_rv32) \ -isystem $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/include/c++/$(LIBCPP_VERSION_rv32)/riscv64-unknown-elf @@ -330,8 +345,8 @@ override WLFLAGS_rv32imc += $(WLFLAGS_rv32) override WLFLAGS_rv32imac += $(WLFLAGS_rv32) override SYSTEM_LIBS_rv32i += \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libc.a \ + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libm.a override SYSTEM_LIBS_CXX_rv32i += \ $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32i/ilp32/libstdc++.a \ @@ -339,8 +354,8 @@ override SYSTEM_LIBS_CXX_rv32i += \ $(LIBCPP_BASE_DIR_rv32)/riscv/lib/gcc/riscv64-unknown-elf/$(LIBCPP_VERSION_rv32)/rv32i/ilp32/libgcc.a override SYSTEM_LIBS_rv32imc += \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libc.a \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libm.a + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libc.a \ + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libm.a override SYSTEM_LIBS_CXX_rv32imc += \ $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32im/ilp32/libstdc++.a \ @@ -348,8 +363,8 @@ override SYSTEM_LIBS_CXX_rv32imc += \ $(LIBCPP_BASE_DIR_rv32)/riscv/lib/gcc/riscv64-unknown-elf/$(LIBCPP_VERSION_rv32)/rv32im/ilp32/libgcc.a override SYSTEM_LIBS_rv32imac += \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libc.a \ - $(NEWLIB_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libm.a + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libc.a \ + $(TOCK_LIBC_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libm.a override SYSTEM_LIBS_CXX_rv32imac += \ $(LIBCPP_BASE_DIR_rv32)/riscv/riscv64-unknown-elf/lib/rv32imac/ilp32/libstdc++.a \ @@ -396,11 +411,20 @@ else ifeq ($(CC_cortex-m_version_major),13) else NEWLIB_VERSION_cortex-m := 4.3.0.20230120 endif -NEWLIB_VERSION_cortex-m0 := $(NEWLIB_VERSION_cortex-m) -NEWLIB_VERSION_cortex-m3 := $(NEWLIB_VERSION_cortex-m) -NEWLIB_VERSION_cortex-m4 := $(NEWLIB_VERSION_cortex-m) -NEWLIB_VERSION_cortex-m7 := $(NEWLIB_VERSION_cortex-m) -NEWLIB_BASE_DIR_cortex-m := $(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-$(NEWLIB_VERSION_cortex-m) + +ifeq ($(PICOLIB),) + # Use newlib + TOCK_LIBC_FOLDER_cortex-m := libtock-newlib-$(NEWLIB_VERSION_cortex-m) +else + # Use picolib + TOCK_LIBC_FOLDER_cortex-m := libtock-picolib-1.8.5 +endif + +TOCK_LIBC_FOLDER_cortex-m0 := $(TOCK_LIBC_FOLDER_cortex-m) +TOCK_LIBC_FOLDER_cortex-m3 := $(TOCK_LIBC_FOLDER_cortex-m) +TOCK_LIBC_FOLDER_cortex-m4 := $(TOCK_LIBC_FOLDER_cortex-m) +TOCK_LIBC_FOLDER_cortex-m7 := $(TOCK_LIBC_FOLDER_cortex-m) +TOCK_LIBC_BASE_DIR_cortex-m := $(TOCK_USERLAND_BASE_DIR)/lib/$(TOCK_LIBC_FOLDER_cortex-m) # Match compiler version to supported libtock-libc++ versions. ifeq ($(CC_cortex-m_version_major),10) @@ -441,7 +465,7 @@ override CPPFLAGS_cortex-m += \ -msingle-pic-base\ -mpic-register=r9\ -mno-pic-data-is-text-relative\ - -isystem $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/include\ + -isystem $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/include\ -isystem $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/include/c++/$(LIBCPP_VERSION_cortex-m)\ -isystem $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/include/c++/$(LIBCPP_VERSION_cortex-m)/arm-none-eabi @@ -460,8 +484,8 @@ override CPPFLAGS_cortex-m7 += $(CPPFLAGS_cortex-m) \ -mcpu=cortex-m7 override SYSTEM_LIBS_cortex-m0 += \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libc.a \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libm.a + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libc.a \ + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libm.a override SYSTEM_LIBS_CXX_cortex-m0 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v6-m/nofp/libstdc++.a \ @@ -469,8 +493,8 @@ override SYSTEM_LIBS_CXX_cortex-m0 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v6-m/nofp/libgcc.a override SYSTEM_LIBS_cortex-m3 += \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libc.a \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libm.a + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libc.a \ + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libm.a override SYSTEM_LIBS_CXX_cortex-m3 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7-m/nofp/libstdc++.a \ @@ -478,8 +502,8 @@ override SYSTEM_LIBS_CXX_cortex-m3 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v7-m/nofp/libgcc.a override SYSTEM_LIBS_cortex-m4 += \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \ + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a override SYSTEM_LIBS_CXX_cortex-m4 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libstdc++.a \ @@ -487,8 +511,8 @@ override SYSTEM_LIBS_CXX_cortex-m4 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/lib/gcc/arm-none-eabi/$(LIBCPP_VERSION_cortex-m)/thumb/v7e-m/nofp/libgcc.a override SYSTEM_LIBS_cortex-m7 += \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \ - $(NEWLIB_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libc.a \ + $(TOCK_LIBC_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a override SYSTEM_LIBS_CXX_cortex-m7 += \ $(LIBCPP_BASE_DIR_cortex-m)/arm/arm-none-eabi/lib/thumb/v7e-m/nofp/libstdc++.a \ diff --git a/Precompiled.mk b/Precompiled.mk index 9545c06bc..757118a6d 100644 --- a/Precompiled.mk +++ b/Precompiled.mk @@ -44,8 +44,8 @@ RISCV_ARCHS := rv32i/ilp32 rv32im/ilp32 rv32imac/ilp32 # - $(3): Arch define PRECOMPILED_NEWLIB_RULES -TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libc.a -TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libm.a +TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-%/$(1)/$(2)/lib/$(3)/libc.a +TOCK_NEWLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-newlib-%/$(1)/$(2)/lib/$(3)/libm.a endef @@ -55,10 +55,45 @@ $(foreach arch,$(RISCV_ARCHS),$(eval $(call PRECOMPILED_NEWLIB_RULES,riscv,riscv # Target to download and extract newlib. # -# % will match something like "libtock-newlib-4.2.0.20211231" which we then -# strip down to just the version with some string manipulation. +# `$*` will match the version number in the libtock-newlib folder name +# (something like "libtock-newlib-4.2.0.20211231"). $(TOCK_NEWLIB_TARGETS): - cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-newlib.sh $(patsubst libtock-newlib-%,%,$*) + cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-newlib.sh $* + +################################################################################ +# Picolib Rules +# +# These pre-compiled archives were created using the libtock-c/picolib folder. +################################################################################ + +# Rule to ensure that the picolib libraries for an architecture exist. +# +# Need to list all libraries which are possible targets into one variable. It is +# imperative that the wildcard `%` expands to the same value for every target to +# tell make that one invocation of this build rule will make all the target +# files. +# +# Arguments: +# - $(1): Family +# - $(2): Toolchain +# - $(3): Arch +define PRECOMPILED_PICOLIB_RULES + +TOCK_PICOLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-picolib-%/$(1)/$(2)/lib/$(3)/libc.a +TOCK_PICOLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/libtock-picolib-%/$(1)/$(2)/lib/$(3)/libm.a + +endef + +TOCK_PICOLIB_TARGETS := +$(foreach arch,$(ARM_ARCHS),$(eval $(call PRECOMPILED_PICOLIB_RULES,arm,arm-none-eabi,$(arch)))) +$(foreach arch,$(RISCV_ARCHS),$(eval $(call PRECOMPILED_PICOLIB_RULES,riscv,riscv64-unknown-elf,$(arch)))) + +# Target to download and extract picolib. +# +# `$*` will match the version number in the libtock-picolib folder name +# (something like "libtock-picolib-1.8.5"). +$(TOCK_PICOLIB_TARGETS): + cd $(TOCK_USERLAND_BASE_DIR)/lib; ./fetch-picolib.sh $* ################################################################################ # LIBC++ Rules @@ -75,7 +110,7 @@ TOCK_CXXLIB_TARGETS += $$(TOCK_USERLAND_BASE_DIR)/lib/%/$(1)/$(2)/lib/$(3)/libsu # So this is supremely frustrating. The issue boils down to limitations of # pattern rules in make. # -# First: pattern rules are implicitly groups, and you aren't allowed to +# First: pattern rules are implicitly groups, and you aren't allowed to # use the :g operator to merge groups. What this means in practice is that # if you have many targets that are all generated by the same rule (i.e., # our unzip creates all the library archive targets), all of the targets diff --git a/lib/fetch-picolib.sh b/lib/fetch-picolib.sh new file mode 100755 index 000000000..38f75f7bf --- /dev/null +++ b/lib/fetch-picolib.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +PICOLIB_VERSION=$1 + +if [ $PICOLIB_VERSION = "1.8.5" ]; then + PICOLIB_SHA="5168a7ea6522717ec5867e0105a224fe7e3779371b095deedc2cd58da369d8cc" +fi + +# Name of the pre-created compiled directories. +ZIP_FILE=libtock-picolib-$PICOLIB_VERSION.zip + +# List of mirrors we support. +MIRRORS=(\ + "https://www.cs.virginia.edu/~bjc8c/archive/tock"\ + "https://alpha.mirror.svc.schuermann.io/files"\ +) + +let FOUND=0 + +# Try from each mirror until we successfully download a .zip file. +for MIRROR in ${MIRRORS[@]}; do + URL=$MIRROR/$ZIP_FILE + echo "Fetching picolib from ${MIRROR}..." + echo " Fetching ${URL}..." + wget -q "$URL" && (echo "$PICOLIB_SHA $ZIP_FILE" | sha256sum -c) + if [ $? -ne 0 ]; then + echo " WARNING: Fetching picolib from mirror $MIRROR failed!" >&2 + else + let FOUND=1 + break + fi +done + +if [[ $FOUND -ne 0 ]]; then + unzip $ZIP_FILE +else + echo "ERROR: Unable to find tock-picolib" + exit -1 +fi diff --git a/libtock-sync/sys.c b/libtock-sync/sys.c index a26a1cafd..d1921bb06 100644 --- a/libtock-sync/sys.c +++ b/libtock-sync/sys.c @@ -1,5 +1,7 @@ #include "interface/console.h" +#include "tock_sys.h" + // XXX Suppress missing prototype warnings for this file as the headers should // be in newlib internals, but first stab at including things didn't quite work // and the warnings are just noise @@ -11,8 +13,6 @@ // SYNCHRONOUS LIBC SUPPORT STUBS // ------------------------------ -int _write(__attribute__ ((unused)) int fd, const void* buf, uint32_t count) { - int written; - libtocksync_console_write((const uint8_t*) buf, count, &written); - return written; +int _write(int fd, const void* buf, uint32_t count) { + return _tock_write(fd, buf, count); } diff --git a/libtock-sync/tock_sys.c b/libtock-sync/tock_sys.c new file mode 100644 index 000000000..be5df3644 --- /dev/null +++ b/libtock-sync/tock_sys.c @@ -0,0 +1,18 @@ +#include "interface/console.h" + +// XXX Suppress missing prototype warnings for this file as the headers should +// be in newlib internals, but first stab at including things didn't quite work +// and the warnings are just noise +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + +// ------------------------------ +// SYNCHRONOUS LIBC SUPPORT STUBS +// ------------------------------ + +int _tock_write(__attribute__ ((unused)) int fd, const void* buf, uint32_t count) { + int written; + libtocksync_console_write((const uint8_t*) buf, count, &written); + return written; +} diff --git a/libtock-sync/tock_sys.h b/libtock-sync/tock_sys.h new file mode 100644 index 000000000..bd5fb624d --- /dev/null +++ b/libtock-sync/tock_sys.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +int _tock_write(int fd, const void* buf, uint32_t count); + +#ifdef __cplusplus +} +#endif diff --git a/libtock/sys.c b/libtock/sys.c index 0a81e819c..7d334788f 100644 --- a/libtock/sys.c +++ b/libtock/sys.c @@ -4,6 +4,7 @@ #include "interface/console.h" #include "tock.h" +#include "tock_sys.h" // XXX Suppress unused parameter warnings for this file as the implementations // are currently all just stubs @@ -28,29 +29,9 @@ void* __dso_handle = 0; int _unlink(const char* pathname) { return -1; } - -int _isatty(int fd) { - if (fd == 0) { - return 1; - } - return 0; -} int _open(const char* path, int flags, ...) { return -1; } -int _close(int fd) { - return -1; -} -int _fstat(int fd, struct stat* st) { - st->st_mode = S_IFCHR; - return 0; -} -int _lseek(int fd, uint32_t offset, int whence) { - return 0; -} -int _read(int fd, void* buf, uint32_t count) { - return 0; // k_read(fd, (uint8_t*) buf, count); -} void _exit(int __status) { tock_exit((uint32_t) __status); } @@ -61,12 +42,22 @@ int _kill(pid_t pid, int sig) { return -1; } +// FOR NEWLIB +int _fstat(int fd, struct stat* st) { + return _tock_fstat(fd, st); +} +int _isatty(int fd) { + return _tock_isatty(fd); +} +int _read(int fd, void* buf, uint32_t count) { + return _tock_read(fd, buf, count); +} +int _lseek(int fd, uint32_t offset, int whence) { + return _tock_lseek(fd, offset, whence); +} +int _close(int fd) { + return _tock_close(fd); +} caddr_t _sbrk(int incr) { - memop_return_t ret; - ret = memop(1, incr); - if (ret.status != TOCK_STATUSCODE_SUCCESS) { - errno = ENOMEM; - return (caddr_t) -1; - } - return (caddr_t) ret.data; + return _tock_sbrk(incr); } diff --git a/libtock/tock_sys.c b/libtock/tock_sys.c new file mode 100644 index 000000000..0dabd8966 --- /dev/null +++ b/libtock/tock_sys.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "tock.h" + +// XXX Suppress unused parameter warnings for this file as the implementations +// are currently all just stubs +#pragma GCC diagnostic ignored "-Wunused-parameter" + +// XXX Suppress missing prototype warnings for this file as the headers should +// be in newlib internals, but first stab at including things didn't quite work +// and the warnings are just noise +#pragma GCC diagnostic ignored "-Wmissing-declarations" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" + +int _tock_close(int fd) { + return -1; +} + +int _tock_lseek(int fd, uint32_t offset, int whence) { + return 0; +} + +int _tock_read(int fd, void* buf, uint32_t count) { + return 0; +} + +int _tock_isatty(int fd) { + if (fd == 0) { + return 1; + } + return 0; +} + +int _tock_fstat(int fd, struct stat* st) { + st->st_mode = S_IFCHR; + return 0; +} + +caddr_t _tock_sbrk(int incr) { + memop_return_t ret; + ret = memop(1, incr); + if (ret.status != TOCK_STATUSCODE_SUCCESS) { + errno = ENOMEM; + return (caddr_t) -1; + } + return (caddr_t) ret.data; +} diff --git a/libtock/tock_sys.h b/libtock/tock_sys.h new file mode 100644 index 000000000..1b5ccdfce --- /dev/null +++ b/libtock/tock_sys.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include "tock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int _tock_close(int fd); +int _tock_lseek(int fd, uint32_t offset, int whence); +int _tock_read(int fd, void* buf, uint32_t count); +int _tock_isatty(int fd); +int _tock_fstat(int fd, struct stat* st); +caddr_t _tock_sbrk(int incr); + +#ifdef __cplusplus +} +#endif diff --git a/picolib-tock/Makefile b/picolib-tock/Makefile new file mode 100644 index 000000000..e86c76ada --- /dev/null +++ b/picolib-tock/Makefile @@ -0,0 +1,11 @@ +# Base folder definitions +TOCK_USERLAND_BASE_DIR ?= .. +LIBNAME := picolib-tock +$(LIBNAME)_DIR := $(TOCK_USERLAND_BASE_DIR)/$(LIBNAME) + +# List all C and Assembly files +$(LIBNAME)_SRCS := $(wildcard $($(LIBNAME)_DIR)/*.c) + +override CPPFLAGS_$(LIBNAME) += -I$(TOCK_USERLAND_BASE_DIR)/libtock + +include $(TOCK_USERLAND_BASE_DIR)/TockLibrary.mk diff --git a/picolib-tock/README.md b/picolib-tock/README.md new file mode 100644 index 000000000..7afa5180a --- /dev/null +++ b/picolib-tock/README.md @@ -0,0 +1,19 @@ +Picolib - Tock Library +====================== + +This library provides helper functions to connect picolib system functions to +Tock-provided functions. + +Specifically, picolib expects these functions: + +- `int fstat(int fd, struct stat *st)` +- `int isatty(int fd)` +- `int read(int fd, void *buf, uint32_t count)` +- `int write(int fd, const void *buf, uint32_t count)` +- `int lseek(int fd, uint32_t offset, int whence)` +- `int close(int fd)` +- `caddr_t sbrk(int incr)` + +These names are different from what newlib expects. Since the underscore +versions are less likely to conflict, we include those functions in libtock +directly, and then only include this library when picolib is being used. diff --git a/picolib-tock/picolib-tock.c b/picolib-tock/picolib-tock.c new file mode 100644 index 000000000..80da51ecc --- /dev/null +++ b/picolib-tock/picolib-tock.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include +#include +#include + +// Suppress missing prototype warnings for this file as the headers should be in +// picolib internals. +#pragma GCC diagnostic ignored "-Wmissing-prototypes" + +int __errno_global; +int* __errno(void) { + return &__errno_global; +} + +// FOR PICOLIB +int fstat(int fd, struct stat* st) { + return _tock_fstat(fd, st); +} +int isatty(int fd) { + return _tock_isatty(fd); +} +int read(int fd, void* buf, uint32_t count) { + return _tock_read(fd, buf, count); +} +int write(int fd, const void* buf, uint32_t count) { + return _tock_write(fd, buf, count); +} +int lseek(int fd, uint32_t offset, int whence) { + return _tock_lseek(fd, offset, whence); +} +int close(int fd) { + return _tock_close(fd); +} +caddr_t sbrk(int incr) { + return _tock_sbrk(incr); +} diff --git a/picolib/.gitignore b/picolib/.gitignore new file mode 100644 index 000000000..855b824ba --- /dev/null +++ b/picolib/.gitignore @@ -0,0 +1,3 @@ +libtock-picolib* +picolib-* +picolibc-* diff --git a/picolib/Makefile b/picolib/Makefile new file mode 100644 index 000000000..5291b7584 --- /dev/null +++ b/picolib/Makefile @@ -0,0 +1,49 @@ +all: rebuild-picolib + +ifeq ($(PICOLIB_VERSION),) + $(error Need to set the PICOLIB_VERSION variable to choose which to build.) +endif + +picolib-$(PICOLIB_VERSION).tar.xz: + @echo "Downloading picolib source $(@F)" + @wget -q -O $@ https://github.com/picolibc/picolibc/releases/download/$(PICOLIB_VERSION)/picolibc-$(PICOLIB_VERSION).tar.xz + +picolibc-$(PICOLIB_VERSION): picolib-$(PICOLIB_VERSION).tar.xz + @echo "Extracting $(.zip` will contain the built libraries. You can move +that folder to the `libtock-c/lib` directory to use the new version of newlib. + +### Docker + +To help with reproducibility, we provide Dockerfiles for various versions of +newlib that can generate the compiled version of libtock-picolib. + +```bash +cd docker/docker-picolib- +./docker-create.sh +``` diff --git a/picolib/build-arm.sh b/picolib/build-arm.sh new file mode 100755 index 000000000..d55ac68e2 --- /dev/null +++ b/picolib/build-arm.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -x + +PICOLIB_SRC_DIR=$1 +PICOLIB_INSTALL_DIR=$2 + +# We want to end up with newlib compiled for at least the `v6-m/nofp`, +# `v7-m/nofp`, and `v7e-m/nofp` architectures. For that to happen the +# arm-none-eabi-gcc compiler must have been compiled with multilib support for +# those architectures. We verify that here before actually building anything. +if ! arm-none-eabi-gcc --print-multi-lib | grep -q 'v6-m/nofp'; then + echo "ERROR: arm-none-eabi-gcc not configured with multilib support for v6-m/nofp" + exit -1 +fi +if ! arm-none-eabi-gcc --print-multi-lib | grep -q 'v7-m/nofp'; then + echo "ERROR: arm-none-eabi-gcc not configured with multilib support for v7-m/nofp" + exit -1 +fi +if ! arm-none-eabi-gcc --print-multi-lib | grep -q 'v7e-m/nofp'; then + echo "ERROR: arm-none-eabi-gcc not configured with multilib support for v7e-m/nofp" + exit -1 +fi + +# Picolibc Configure Flags +# +# picolib=false # Do not use picolib sbrk. We need to use the memop syscalls. +# picocrt=false # Do not build crt0, we have our own. +# picocrt-lib=false # Do not package crt0. +# tinystdio=false # Do not use AVR tinystdio, which uses a different underlying interface (aka stdout object). +# newlib-stdio64=false # Do not include 64 bit APIs. +# newlib-reent-small=true # Disable reentrancy support to save space +# newlib-global-atexit=true # Disable reentrancy for `atexit` (saves space) +$PICOLIB_SRC_DIR/scripts/do-configure arm-none-eabi -Dprefix=`realpath $PICOLIB_INSTALL_DIR` \ + -Dpicolib=false \ + -Dpicocrt=false \ + -Dpicocrt-lib=false \ + -Dtinystdio=false \ + -Dnewlib-stdio64=false \ + -Dnewlib-reent-small=true \ + -Dnewlib-global-atexit=true \ + -Dmultilib-list=thumb/v6-m/nofp,thumb/v7-m/nofp,thumb/v7e-m/nofp \ + -Dc_args="-g -Os -ffunction-sections -fdata-sections -fPIC -msingle-pic-base -mno-pic-data-is-text-relative" + +ninja +ninja install diff --git a/picolib/build-riscv.sh b/picolib/build-riscv.sh new file mode 100755 index 000000000..fe51421c6 --- /dev/null +++ b/picolib/build-riscv.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -x + +PICOLIB_SRC_DIR=$1 +PICOLIB_INSTALL_DIR=$2 + +$PICOLIB_SRC_DIR/scripts/do-configure riscv64-unknown-elf -Dprefix=`realpath $PICOLIB_INSTALL_DIR` \ + -Dpicolib=false \ + -Dpicocrt=false \ + -Dpicocrt-lib=false \ + -Dtinystdio=false \ + -Dnewlib-stdio64=false \ + -Dmultilib-list=rv32i/ilp32,rv32im/ilp32,rv32imac/ilp32 \ + -Dnewlib-reent-small=true \ + -Dnewlib-global-atexit=true + +ninja +ninja install diff --git a/picolib/docker/docker-picolib-1.8.5/Dockerfile b/picolib/docker/docker-picolib-1.8.5/Dockerfile new file mode 100644 index 000000000..b83c1ae16 --- /dev/null +++ b/picolib/docker/docker-picolib-1.8.5/Dockerfile @@ -0,0 +1,28 @@ +### +### Dockerfile to build libtock-picolib-1.8.5 +### + +# We get version 12 of arm-none-eabi-gcc/riscv64-unknown-elf-gcc. +FROM debian:bookworm + +LABEL maintainer="Tock Project Developers " +LABEL version="0.1" +LABEL description="Dockerfile to build libtock-c picolib 1.8.5." + +# Disable Prompt During Packages Installation +ARG DEBIAN_FRONTEND=noninteractive +# Update Ubuntu Software repository +RUN apt update + +# Install our toolchains +RUN apt install -y gcc-arm-none-eabi gcc-riscv64-unknown-elf + +# Install needed tools +RUN apt install -y git build-essential ninja-build meson zip + +# Clone the libtock-c source so we can use the build scripts +RUN git clone https://github.com/tock/libtock-c -b make-precompiled-picolib +RUN cd libtock-c && git fetch && git checkout 6dc8907938e7daa307650ba6577a59c25214ef3f + +# Actually build the toolchain +RUN cd libtock-c/picolib && make PICOLIB_VERSION=1.8.5 diff --git a/picolib/docker/docker-picolib-1.8.5/docker-create.sh b/picolib/docker/docker-picolib-1.8.5/docker-create.sh new file mode 100755 index 000000000..71fb33f0c --- /dev/null +++ b/picolib/docker/docker-picolib-1.8.5/docker-create.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +docker build -t libtock-c-picolib-1.8.5 . +id=$(docker create libtock-c-picolib-1.8.5) +docker cp $id:/libtock-c/newlib/libtock-picolib-1.8.5.zip libtock-picolib-1.8.5.zip