diff --git a/Docker/Dockerfile b/Docker/Dockerfile new file mode 100644 index 0000000..e243249 --- /dev/null +++ b/Docker/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:noble AS builder + +# Install Make, g++, verilator, the RISC-V toolchain and the picolibc library +RUN apt-get update + +RUN apt-get install -qy --no-install-recommends make g++ bsdmainutils verilator gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf + + +# NOTE: the random forces a Docker cache miss to force +# the execution of the script +ADD "https://www.random.org/cgi-bin/randbyte?nbytes=10&format=h" skipcache + +# Now compile and simulate +WORKDIR /build +COPY ./ /build + +RUN USE_PICOLIBC=1 make prof 2>&1 | tee -a sloth_build.log +RUN tar -czvf docker_build.tar.gz sloth_build.log core_pc.log firmware.pmap firmware.bin firmware.elf firmware.hex _prof _build drv slh --transform 's,^,docker_build/,' + +# Copy the produced artifacts to the host +FROM scratch AS artifacts +COPY --from=builder /build/docker_build.tar.gz ./docker_build.tar.gz diff --git a/Makefile b/Makefile index 9ca8675..671b920 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,15 @@ CCONF_H ?= config.h XCHAIN ?= riscv64-unknown-elf- CFLAGS = -O2 -Wall -g -mabi=ilp32 -march=rv32imc CFLAGS += -include $(CCONF_H) -DNDEBUG -LDFLAGS = -Wl,-Bstatic,-T,flow/riscv.ld,--no-relax +# If we use picolibc, adapt the flags. +# NOTE: the local ld script mostly provides flash and RAM layout +# (in our case flash starts at 0 and is in fact part of RAM) +ifeq ($(USE_PICOLIBC),1) + CFLAGS += -specs=picolibc.specs + LDFLAGS = -Wl,-Bstatic,-T,flow/picolibc.ld,--no-relax +else + LDFLAGS = -Wl,-Bstatic,-T,flow/riscv.ld,--no-relax +endif KATNUM ?= 10 CFLAGS += -DKATNUM=$(KATNUM) @@ -136,6 +144,7 @@ clean: $(RM) -f $(FW).* $(CCONF_H) $(OBJS) $(VVP) $(RM) -rf $(PROF) $(BUILD) $(RM) -f *.jou *.log *.bit + $(MAKE) -f Makefile.docker clean cd slh && $(MAKE) clean cd flow/yosys-syn && $(MAKE) clean diff --git a/Makefile.docker b/Makefile.docker new file mode 100644 index 0000000..33d8791 --- /dev/null +++ b/Makefile.docker @@ -0,0 +1,19 @@ +ifeq ($(DOCKER_FORCE_REBUILD),1) +NOCACHE=--no-cache +RECREATE=--force-recreate +else +NOCACHE= +RECREATE= +endif +ifeq ($(DOCKER_VERBOSE),1) +BUILDKIT_PROGRESS=plain +endif + +DOCKER_PLATFORM=--platform linux/amd64 + +all: + DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=$(BUILDKIT_PROGRESS) docker build --build-arg PLATFORMS="$(PLATFORMS)" --file Docker/Dockerfile -o type=local,dest=Docker/ . + +clean: + # Remove build artifacts + @rm -f Docker/docker_build.tar.gz diff --git a/README.md b/README.md index 7890ea6..7473c4c 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,13 @@ See [slh/README.md](slh/README.md) for more information. As a prerequisite for simulation, you'll need: -* [Verilator](https://github.com/verilator/verilator) verilog simulator. +* [Verilator](https://github.com/verilator/verilator) verilog simulator. This might be packaged on some Linux distros. * A RISC-V cross-compiler that supports bare-metal targets. You can build a suitable [riscv-gnu-toolchain](https://github.com/riscv/riscv-gnu-toolchain) -with `./configure --enable-multilib` and `make newlib`. +with `./configure --enable-multilib` and `make newlib`. Under some Linux based distros (such as Debian), it is possible to use the packaged +`gcc-riscv64-unknown-elf` along with the packaged `picolibc-riscv64-unknown-elf`: note that in this case, you will have to export the `USE_PICOLIBC=1` environment +variable when compiling: `USE_PICOLIBC=1 make veri` (this is due to some divergence between `newlib` and `picolibc` C standard libraries linking scripts). -Both of these may be available as packages for Linux operating systems. The name of your toolchain is set in `XCHAIN` variable in the [Makefile](Makefile). +The name of your toolchain is set in `XCHAIN` variable in the [Makefile](Makefile). To build and run a quick end-to-end test, try: ``` @@ -107,6 +109,16 @@ exit() ``` The readout from this particular execution of SLH-DSA-SHAKE-128f is that KeyGen was 204310 cycles, signing was 4943111 cycles, and verification was 434660 cycles. Furthermore, the self-tests were a PASS; the output matched the Known Answer Tests. Modify the end of `test_bench.c` to have broader test behavior. +## Using Docker + +Alternatively, it is possible to use an Ubuntu based Docker container for the simulation (with preinstalled verilator and toolchain). Having Docker installed, simply execute: + + +``` +DOCKER_VERBOSE=1 make -f Makefile.docker +``` + +This will put the compilation and profiling artifacts in the compressed `Docker/docker_build.tar.gz` file. ## Some other targets diff --git a/drv/main.c b/drv/main.c index 02c8bfd..f529f09 100644 --- a/drv/main.c +++ b/drv/main.c @@ -18,6 +18,36 @@ int test_sloth(); // test_sloth.c int test_bench(); // test_bench.c int test_leak(); // test_leak.c +#ifdef _PICOLIBC__ +// XXX In case of Picolibc, redirect stdio related stuff to uart +// (see https://github.com/picolibc/picolibc/blob/main/doc/os.md) +// This allows to use printf family of functions +#include +#include +static int sample_putc(char c, FILE *file) +{ + (void) file; /* Not used in this function */ + sio_putc(c); /* Defined by underlying system */ + return c; +} + +static int sample_getc(FILE *file) +{ + unsigned char c; + (void) file; /* Not used in this function */ + c = sio_getc(); /* Defined by underlying system */ + return c; +} + +FILE __stdio = FDEV_SETUP_STREAM(sample_putc, + sample_getc, + NULL, + _FDEV_SETUP_RW); + +FILE *const stdin = &__stdio; __strong_reference(stdin, stdout); __strong_reference(stdin, stderr); +#endif + + int main() { int fail = 0; @@ -68,6 +98,11 @@ int main() sio_putc(4); // translated to EOF sio_putc(0); +#ifdef _PICOLIBC__ + // XXX: in case of picolibc, explicitly exit as + // this is not performed at the return of main + exit(0); +#endif return 0; } diff --git a/flow/eprof.py b/flow/eprof.py index e4de51e..1d17933 100755 --- a/flow/eprof.py +++ b/flow/eprof.py @@ -55,8 +55,13 @@ def cnt_str(cnt): for rfn in lsc: pfl=len(os.path.commonprefix([os.getcwd(), rfn])) wfn = rfn[pfl:].replace("/","_"); + try: + # Try to open the source file, if not possible skip it + fr = open(rfn, "r") + except: + print("[-] Skipping %s (not found)" % rfn) + continue print("writing:", wfn) - fr = open(rfn, "r") fw = open(wfn, "w") ln = 0 for sf in fr: diff --git a/flow/picolibc.ld b/flow/picolibc.ld new file mode 100644 index 0000000..937c4c6 --- /dev/null +++ b/flow/picolibc.ld @@ -0,0 +1,6 @@ +# XXX: sizes to be fixed according to the (hardware) allocated RAM size of SLotH +__flash = 0x00000000; +__flash_size = 64k; +__ram = __flash + __flash_size; +__ram_size = 64k; +__stack_size = 8k;