From c688ab4bb45cdd958b5313c2bdaf84eef0f2d271 Mon Sep 17 00:00:00 2001 From: Robot Date: Sun, 30 Jun 2024 16:30:25 +0200 Subject: [PATCH] Major refactor I somehow forgot about and futile attemt to fix I2C (#75) * Major refactor I somehow forgot about and futile attemt to fix I2C * Replace hal/misc.h * Use macros to disable stdlib from gpio_ll.h * Tidy the clang --- .gitmodules | 2 +- Makefile | 7 +- {kernel/include => common}/badgelib/arrays.h | 0 .../include => common}/badgelib/assertions.h | 0 .../include => common}/badgelib/attributes.h | 5 +- .../include => common}/badgelib/badge_err.h | 15 +- .../badgelib/badge_strings.h | 0 {kernel/include => common}/badgelib/list.h | 0 {kernel/include => common}/badgelib/meta.h | 0 common/compiler.cmake | 28 ++ common/{ => include}/errno.h | 0 {kernel => common}/include/hal/gpio.h | 16 +- {kernel => common}/include/hal/i2c.h | 7 +- {kernel => common}/include/hal/spi.h | 13 +- common/{ => include}/signal.h | 0 common/{ => include}/sys/wait.h | 0 common/{ => include}/syscall.h | 18 + common/include/syscall_defs.inc | 222 +++++++++ common/syscall_defs.inc | 130 ------ files/CMakeLists.txt | 53 +++ files/Makefile | 19 +- files/{ => bak}/init/CMakeLists.txt | 3 +- files/{ => bak}/init/Makefile | 0 files/{ => bak}/init/src/main.c | 0 files/{ => bak}/init/src/start.S | 0 files/{ => bak}/init/src/syscall.c | 0 files/{ => bak}/test/CMakeLists.txt | 0 files/{ => bak}/test/Makefile | 0 files/{ => bak}/test/src/main.c | 0 files/{ => bak}/test/src/start.S | 0 files/{ => bak}/test/src/syscall.c | 0 files/lib/CMakeLists.txt | 8 + files/lib/badge/CMakeLists.txt | 4 + files/lib/crt/CMakeLists.txt | 10 + files/lib/crt/start.S | 47 ++ files/lib/syscall/CMakeLists.txt | 14 + files/lib/syscall/src/gpio.c | 49 ++ files/lib/syscall/src/i2c.c | 36 ++ files/lib/syscall/src/spi.c | 46 ++ files/lib/syscall/src/syscall.c | 15 + files/sbin/CMakeLists.txt | 6 + files/sbin/init/CMakeLists.txt | 9 + files/sbin/init/main.c | 95 ++++ kernel/CMakeLists.txt | 47 +- kernel/Makefile | 3 +- kernel/cpu/riscv/CMakeLists.txt | 1 + kernel/cpu/riscv/include/cpu/isr.h | 13 +- kernel/cpu/riscv/src/isr.c | 2 +- kernel/cpu/riscv/src/panic.c | 6 + kernel/cpu/riscv/src/syscall.S | 47 ++ kernel/include/interrupt.h | 2 + kernel/include/process/process.h | 2 + kernel/include/syscall_util.h | 28 ++ {lib => kernel/lib}/kbelf | 0 kernel/port/esp32c6/CMakeLists.txt | 7 +- .../port/esp32c6/include/soc/io_mux_struct.h | 6 +- kernel/port/esp32c6/linker.ld | 2 + kernel/port/esp32c6/src/hal/i2c.c | 31 +- kernel/port/esp32c6/src/hal/spi.c | 52 ++- kernel/port/esp32c6/src/interrupt.c | 34 +- kernel/port/esp32c6/src/port.c | 7 + kernel/port/esp32p4/CMakeLists.txt | 6 +- kernel/port/esp32p4/linker.ld | 1 + kernel/port/esp32p4/src/port.c | 4 + kernel/port/esp_common/CMakeLists.txt | 17 +- kernel/port/esp_common/include/esp_assert.h | 2 + kernel/port/esp_common/include/hal/assert.h | 11 + kernel/port/esp_common/include/hal/log.h | 5 + kernel/port/esp_common/include/hal/misc.h | 80 ++++ .../port/esp_common/include/hal/regi2c_ctrl.h | 20 + .../src/hal => esp_common/src}/gpio.c | 107 +++-- kernel/port/esp_common/src/i2c.c | 437 ++++++++++++++++++ kernel/src/badgelib/int_routines.c | 49 ++ kernel/src/hal/syscall_impl.c | 247 ++++++++++ kernel/src/{loading => process}/kbelfx.c | 5 +- kernel/src/process/process.c | 30 +- kernel/src/process/syscall_impl.c | 63 ++- kernel/src/process/syscall_util.c | 35 ++ kernel/src/{ => scheduler}/scheduler.c | 0 kernel/src/scheduler/syscall_impl.c | 9 + kernel/src/syscall.c | 89 ++-- test/e2fs.iso | Bin 2097152 -> 0 bytes test/fatfs.iso | Bin 2097152 -> 0 bytes test/list.c | 390 ---------------- test/proctest | Bin 956 -> 0 bytes test/proctest.S | 14 - test/text1 | 1 - test/text2 | 1 - test/unittest.h | 28 -- test/userlandlib.c | 5 - test/userlandlib.so | Bin 5344 -> 0 bytes test/userlandtest | Bin 6020 -> 0 bytes test/userlandtest.c | 10 - tools/address-filter.py | 2 +- tools/ramfs-gen.py | 1 + tools/readjal.py | 22 - 96 files changed, 2006 insertions(+), 852 deletions(-) rename {kernel/include => common}/badgelib/arrays.h (100%) rename {kernel/include => common}/badgelib/assertions.h (100%) rename {kernel/include => common}/badgelib/attributes.h (90%) rename {kernel/include => common}/badgelib/badge_err.h (92%) rename {kernel/include => common}/badgelib/badge_strings.h (100%) rename {kernel/include => common}/badgelib/list.h (100%) rename {kernel/include => common}/badgelib/meta.h (100%) create mode 100644 common/compiler.cmake rename common/{ => include}/errno.h (100%) rename {kernel => common}/include/hal/gpio.h (71%) rename {kernel => common}/include/hal/i2c.h (93%) rename {kernel => common}/include/hal/spi.h (70%) rename common/{ => include}/signal.h (100%) rename common/{ => include}/sys/wait.h (100%) rename common/{ => include}/syscall.h (85%) create mode 100644 common/include/syscall_defs.inc delete mode 100644 common/syscall_defs.inc create mode 100644 files/CMakeLists.txt rename files/{ => bak}/init/CMakeLists.txt (96%) rename files/{ => bak}/init/Makefile (100%) rename files/{ => bak}/init/src/main.c (100%) rename files/{ => bak}/init/src/start.S (100%) rename files/{ => bak}/init/src/syscall.c (100%) rename files/{ => bak}/test/CMakeLists.txt (100%) rename files/{ => bak}/test/Makefile (100%) rename files/{ => bak}/test/src/main.c (100%) rename files/{ => bak}/test/src/start.S (100%) rename files/{ => bak}/test/src/syscall.c (100%) create mode 100644 files/lib/CMakeLists.txt create mode 100644 files/lib/badge/CMakeLists.txt create mode 100644 files/lib/crt/CMakeLists.txt create mode 100644 files/lib/crt/start.S create mode 100644 files/lib/syscall/CMakeLists.txt create mode 100644 files/lib/syscall/src/gpio.c create mode 100644 files/lib/syscall/src/i2c.c create mode 100644 files/lib/syscall/src/spi.c create mode 100644 files/lib/syscall/src/syscall.c create mode 100644 files/sbin/CMakeLists.txt create mode 100644 files/sbin/init/CMakeLists.txt create mode 100644 files/sbin/init/main.c create mode 100644 kernel/cpu/riscv/src/syscall.S create mode 100644 kernel/include/syscall_util.h rename {lib => kernel/lib}/kbelf (100%) create mode 100644 kernel/port/esp_common/include/hal/assert.h create mode 100644 kernel/port/esp_common/include/hal/log.h create mode 100644 kernel/port/esp_common/include/hal/misc.h create mode 100644 kernel/port/esp_common/include/hal/regi2c_ctrl.h rename kernel/port/{esp32c6/src/hal => esp_common/src}/gpio.c (50%) create mode 100644 kernel/port/esp_common/src/i2c.c create mode 100644 kernel/src/hal/syscall_impl.c rename kernel/src/{loading => process}/kbelfx.c (95%) create mode 100644 kernel/src/process/syscall_util.c rename kernel/src/{ => scheduler}/scheduler.c (100%) create mode 100644 kernel/src/scheduler/syscall_impl.c delete mode 100644 test/e2fs.iso delete mode 100644 test/fatfs.iso delete mode 100644 test/list.c delete mode 100755 test/proctest delete mode 100644 test/proctest.S delete mode 100644 test/text1 delete mode 100644 test/text2 delete mode 100644 test/unittest.h delete mode 100644 test/userlandlib.c delete mode 100755 test/userlandlib.so delete mode 100755 test/userlandtest delete mode 100644 test/userlandtest.c delete mode 100755 tools/readjal.py diff --git a/.gitmodules b/.gitmodules index 7496de3..4670b46 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ [submodule "lib/kbelf"] - path = lib/kbelf + path = kernel/lib/kbelf url = https://github.com/robotman2412/KiloElfLoader [submodule "kernel/port/esp_common/esp-idf"] path = kernel/port/esp_common/esp-idf diff --git a/Makefile b/Makefile index cf688c4..98d706a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ MAKEFLAGS += --silent SHELL := /usr/bin/env bash -.PHONY: all prepare openocd gdb flash monitor clean-all clean build clang-format-check clang-tidy-check +.PHONY: all prepare openocd gdb flash monitor clean build clang-format-check clang-tidy-check all: build @@ -17,10 +17,9 @@ build: $(MAKE) -C files build $(MAKE) -C kernel build -clean-all: clean clean: - $(MAKE) -C files clean-all - $(MAKE) -C kernel clean-all + $(MAKE) -C files clean + $(MAKE) -C kernel clean openocd: $(MAKE) -C kernel openocd diff --git a/kernel/include/badgelib/arrays.h b/common/badgelib/arrays.h similarity index 100% rename from kernel/include/badgelib/arrays.h rename to common/badgelib/arrays.h diff --git a/kernel/include/badgelib/assertions.h b/common/badgelib/assertions.h similarity index 100% rename from kernel/include/badgelib/assertions.h rename to common/badgelib/assertions.h diff --git a/kernel/include/badgelib/attributes.h b/common/badgelib/attributes.h similarity index 90% rename from kernel/include/badgelib/attributes.h rename to common/badgelib/attributes.h index c71c001..77162d9 100644 --- a/kernel/include/badgelib/attributes.h +++ b/common/badgelib/attributes.h @@ -6,6 +6,9 @@ // this file provides convenience macros for the attributes provided by gcc: // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html +// Disable address sanitization for a function. +#define NOASAN __attribute__((no_sanitize("address"))) + // Declares that a function cannot return. #define NORETURN __attribute__((noreturn)) @@ -13,7 +16,7 @@ #define PURE __attribute__((pure)) // Declares that a function has no observable side effects, does not mutate its parameters and does not read memory. -#define CONST __attribute__((pure)) +#define CONST __attribute__((const)) // Declares that a function is not called very often and can be size-optimized even in fast builds. #define COLD __attribute__((cold)) diff --git a/kernel/include/badgelib/badge_err.h b/common/badgelib/badge_err.h similarity index 92% rename from kernel/include/badgelib/badge_err.h rename to common/badgelib/badge_err.h index 7dc570b..0c8aa11 100644 --- a/kernel/include/badgelib/badge_err.h +++ b/common/badgelib/badge_err.h @@ -117,8 +117,7 @@ typedef enum { _badge_ecause_num, } badge_ecause_t; -#include "assertions.h" -#include "log.h" +#include "attributes.h" #include "meta.h" @@ -129,12 +128,14 @@ extern char const *badge_eloc_name[_badge_eloc_num]; extern char const *badge_ecause_name[_badge_ecause_num]; // Get the name of a badge_eloc_t. -char const *badge_eloc_get_name(badge_eloc_t eloc) PURE; +char const *badge_eloc_get_name(badge_eloc_t eloc) CONST; // Get the name of a badge_ecause_t. -char const *badge_ecause_get_name(badge_ecause_t eloc) PURE; +char const *badge_ecause_get_name(badge_ecause_t eloc) CONST; +#ifdef BADGEROS_KERNEL +#include "log.h" // Show a warning message if the error condition fails. #define badge_err_log_warn(ec) \ do { \ @@ -188,17 +189,13 @@ char const *badge_ecause_get_name(badge_ecause_t eloc) PURE; // Assert if the error condition fails in debug mode. #define badge_err_assert_dev(ec) ((void)0) #endif +#endif // Sets `ec` to the given `location` and `cause` values if `ec` is not `NULL`. // `ec` must be a variable name. #define badge_err_set(ec, location_value, cause_value) \ do { \ if ((ec) != NULL) { \ - if (cause_value) { \ - uint32_t pc; \ - asm("auipc %0, 0" : "=r"(pc)); \ - logkf(LOG_DEBUG, "ELOC=%{d}, ECAUSE=%{d}, PC=0x%{size;x}", location_value, cause_value, pc); \ - } \ (ec)->location = location_value; \ (ec)->cause = cause_value; \ } \ diff --git a/kernel/include/badgelib/badge_strings.h b/common/badgelib/badge_strings.h similarity index 100% rename from kernel/include/badgelib/badge_strings.h rename to common/badgelib/badge_strings.h diff --git a/kernel/include/badgelib/list.h b/common/badgelib/list.h similarity index 100% rename from kernel/include/badgelib/list.h rename to common/badgelib/list.h diff --git a/kernel/include/badgelib/meta.h b/common/badgelib/meta.h similarity index 100% rename from kernel/include/badgelib/meta.h rename to common/badgelib/meta.h diff --git a/common/compiler.cmake b/common/compiler.cmake new file mode 100644 index 0000000..1c9e1f3 --- /dev/null +++ b/common/compiler.cmake @@ -0,0 +1,28 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +# The target platform +if(NOT DEFINED ENV{BADGEROS_PORT}) + set(BADGEROS_PORT esp32c6) +else() + set(BADGEROS_PORT $ENV{BADGEROS_PORT}) +endif() + +# Set the C compiler +if(DEFINED CMAKE_C_COMPILER) + message("Using compiler '${CMAKE_C_COMPILER}' from environment") +elseif(DEFINED ENV{CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER $ENV{CMAKE_C_COMPILER}) + message("Using compiler '${CMAKE_C_COMPILER}' from environment") +else() + find_program(CMAKE_C_COMPILER NAMES riscv32-badgeros-linux-gnu-gcc riscv32-unknown-linux-gnu-gcc riscv32-linux-gnu-gcc riscv64-unknown-linux-gnu-gcc riscv64-linux-gnu-gcc REQUIRED) + message("Detected RISC-V C compiler as '${CMAKE_C_COMPILER}'") +endif() + +# Determine the compiler prefix +get_filename_component(compiler_name "${CMAKE_C_COMPILER}" NAME) +string(REGEX MATCH "^([A-Za-z0-9_]+\-)*" BADGER_COMPILER_PREFIX "${compiler_name}") +find_program(BADGER_OBJCOPY NAMES "${BADGER_COMPILER_PREFIX}objcopy" REQUIRED) +find_program(BADGER_OBJDUMP NAMES "${BADGER_COMPILER_PREFIX}objdump" REQUIRED) diff --git a/common/errno.h b/common/include/errno.h similarity index 100% rename from common/errno.h rename to common/include/errno.h diff --git a/kernel/include/hal/gpio.h b/common/include/hal/gpio.h similarity index 71% rename from kernel/include/hal/gpio.h rename to common/include/hal/gpio.h index 3365aed..700b593 100644 --- a/kernel/include/hal/gpio.h +++ b/common/include/hal/gpio.h @@ -36,16 +36,20 @@ typedef enum { // Returns the amount of GPIO pins present. // Cannot produce an error. -#define io_count() (31) +int io_count() CONST; // Sets the mode of GPIO pin `pin` to `mode`. -void io_mode(badge_err_t *ec, int pin, io_mode_t mode); +void io_mode(badge_err_t *ec, int pin, io_mode_t mode); +// Get the mode of GPIO pin `pin`. +io_mode_t io_getmode(badge_err_t *ec, int pin); // Sets the pull resistor behaviour of GPIO pin `pin` to `dir`. -void io_pull(badge_err_t *ec, int pin, io_pull_t dir); +void io_pull(badge_err_t *ec, int pin, io_pull_t dir); +// Get the pull resistor behaviour of GPIO pin `pin`. +io_pull_t io_getpull(badge_err_t *ec, int pin); // Writes level to GPIO pin pin. -void io_write(badge_err_t *ec, int pin, bool level); +void io_write(badge_err_t *ec, int pin, bool level); // Reads logic level value from GPIO pin `pin`. // Returns false on error. -bool io_read(badge_err_t *ec, int pin); +bool io_read(badge_err_t *ec, int pin); // Determine whether GPIO `pin` is claimed by a peripheral. // Returns false on error. -bool io_is_peripheral(badge_err_t *ec, int pin); +bool io_is_peripheral(badge_err_t *ec, int pin); diff --git a/kernel/include/hal/i2c.h b/common/include/hal/i2c.h similarity index 93% rename from kernel/include/hal/i2c.h rename to common/include/hal/i2c.h index 2472b86..5f309f3 100644 --- a/kernel/include/hal/i2c.h +++ b/common/include/hal/i2c.h @@ -10,9 +10,14 @@ #include +// Determines whether an I²C address is valid. +static inline bool i2c_is_valid_addr(int slave_id) { + return slave_id >= 8 && (slave_id & 0xf0) != 0xf0 && slave_id < 1024; +} + // Returns the amount of I²C peripherals present. // Cannot produce an error. -#define i2c_count() (1) +int i2c_count() CONST; /* // Initialises I²C peripheral i2c_num in slave mode with SDA pin sda_pin, SCL pin scl_pin and a write buffer size of at diff --git a/kernel/include/hal/spi.h b/common/include/hal/spi.h similarity index 70% rename from kernel/include/hal/spi.h rename to common/include/hal/spi.h index 8b34b51..453778b 100644 --- a/kernel/include/hal/spi.h +++ b/common/include/hal/spi.h @@ -11,12 +11,15 @@ // Returns the amount of SPI peripherals present. // Cannot produce an error. -#define spi_count() (1) +int spi_count() CONST; -// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin `miso_pin`, SS pin `ss_pin` and clock speed/bitrate -// bitrate. The modes of the SCLK, MOSI, MISO and SS pins are changed automatically. This -// function may be used again to change the settings on an initialised SPI peripheral in controller mode. -void spi_controller_init(badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate); +// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin +// `miso_pin`, SS pin `ss_pin` and clock speed/bitrate bitrate. The modes of the SCLK, MOSI, MISO and SS pins are +// changed automatically. This function may be used again to change the settings on an initialised SPI peripheral in +// controller mode. +void spi_controller_init( + badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate +); // De-initialises SPI peripheral. void spi_deinit(badge_err_t *ec, int spi_num); // Reads len bytes into buffer buf from SPI device. diff --git a/common/signal.h b/common/include/signal.h similarity index 100% rename from common/signal.h rename to common/include/signal.h diff --git a/common/sys/wait.h b/common/include/sys/wait.h similarity index 100% rename from common/sys/wait.h rename to common/include/sys/wait.h diff --git a/common/syscall.h b/common/include/syscall.h similarity index 85% rename from common/syscall.h rename to common/include/syscall.h index 5562d3b..2b965b7 100644 --- a/common/syscall.h +++ b/common/include/syscall.h @@ -11,9 +11,27 @@ #else +#include "hal/gpio.h" + +#include +#include +#include + #ifdef BADGEROS_KERNEL #include "filesystem.h" #include "scheduler/scheduler.h" + +#define SYSCALL_FLAG_EXISTS 0x01 +#define SYSCALL_FLAG_FAST 0x02 + +typedef struct { + void (*funcptr)(); + uint8_t retwidth; + uint8_t flags; +} syscall_info_t; + +syscall_info_t syscall_info(int no); + #else typedef int file_t; typedef int tid_t; diff --git a/common/include/syscall_defs.inc b/common/include/syscall_defs.inc new file mode 100644 index 0000000..3d4c4da --- /dev/null +++ b/common/include/syscall_defs.inc @@ -0,0 +1,222 @@ + +// SPDX-License-Identifier: MIT +// clang-format off + + + +/* ==== DEFAULT MACRO EXPANSIONS ==== */ + +// Normal syscall definition. +#ifndef SYSCALL_DEF +#define SYSCALL_DEF(...) +#endif + +// Normal syscall definition (returning void). +#ifndef SYSCALL_DEF_V +#define SYSCALL_DEF_V(no, enum, name, ...) SYSCALL_DEF(no, enum, name, void, __VA_ARGS__) +#endif + +// Fast syscall definition. +#ifndef SYSCALL_DEF_F +#define SYSCALL_DEF_F(no, enum, name, returns, ...) SYSCALL_DEF(no, enum, name, returns, __VA_ARGS__) +#endif + +// Fast syscall definition (returning void). +#ifndef SYSCALL_DEF_FV +#define SYSCALL_DEF_FV(no, enum, name, ...) SYSCALL_DEF_F(no, enum, name, void, __VA_ARGS__) +#endif + + + +/* ==== THREAD SYSCALLS ==== */ +// Implemented in process/syscall_impl.c + +// Yield to other threads. +SYSCALL_DEF_V(1, SYSCALL_THREAD_YIELD, syscall_thread_yield) + +// // Create a new thread. +// SYSCALL_DEF(2, SYSCALL_THREAD_CREATE, syscall_thread_create, bool, void *entry, void *arg, int priority) + +// // Suspend a thread; it will not run again until resumed. +// SYSCALL_DEF(3, SYSCALL_THREAD_SUSPEND, syscall_thread_suspend, bool, tid_t thread) + +// // Resume a thread; this does nothing if it is already running. +// SYSCALL_DEF(4, SYSCALL_THREAD_RESUME, syscall_thread_resume, bool, tid_t thread) + +// // Detach a thread; the thread will be destroyed as soon as it exits. +// SYSCALL_DEF(5, SYSCALL_THREAD_DETACH, syscall_thread_detach, bool, tid_t thread) + +// // Destroy a thread; it will be stopped and its resources released. +// SYSCALL_DEF(6, SYSCALL_THREAD_DESTROY, syscall_thread_destroy, bool, tid_t thread) + +// // Exit the current thread; exit code can be read unless destroyed or detached. +// SYSCALL_DEF_V(7, SYSCALL_THREAD_EXIT, syscall_thread_exit, int code) + + + +/* ==== PROCESS MANAGEMENT SYSCALLS ==== */ +// Implemented in process/syscall_impl.c + +// Exit the process; exit code can be read by parent process. +SYSCALL_DEF_V(8, SYSCALL_PROC_EXIT, syscall_proc_exit, int code) + +// Get the command-line arguments (i.e. argc+argv) of the current process. +// If memory is large enough, a NULL-terminated argv array of C-string pointers and their data is stored in `memory`. +// The function returns how many bytes would be needed to store the structure. +// If the memory was not large enough, it it not modified. +SYSCALL_DEF(9, SYSCALL_PROC_GETARGS, syscall_proc_getargs, size_t, size_t cap, void *memory) + +// Create a "pre-start" child process that inherits this process' file descriptors and environment variables. +// The child process is created in a halted state and it is killed if the parent exits before the child is resumed. +// Returns process ID of new child on success, or a (negative) errno on failure. +SYSCALL_DEF(10, SYSCALL_PROC_PCREATE, syscall_proc_pcreate, int, char const *binary, int argc, char const *const *argv) + +// Destroy a "pre-start" child process. +// Usually used in case of errors. +SYSCALL_DEF(11, SYSCALL_PROC_PDESTROY, syscall_proc_pdestroy, bool, int child) + +// Starts a "pre-start" child process, thereby converting it into a running child process. +SYSCALL_DEF(12, SYSCALL_PROC_PSTART, syscall_proc_pstart, bool, int child) + +// Set the signal handler for a specific signal number. +SYSCALL_DEF(13, SYSCALL_PROC_SIGHANDLER, syscall_proc_sighandler, void *, int signum, void *newhandler) + +// Return from a signal handler. +SYSCALL_DEF_V(14, SYSCALL_PROC_SIGRET, syscall_proc_sigret) + +// Get child process status update. +SYSCALL_DEF(15, SYSCALL_PROC_WAITPID, syscall_proc_waitpid, int, int pid, int *wstatus, int options) + + +/* ==== FILESYSTEM SYSCALLS ==== */ +// Implemented in filesystem/syscall_impl.c + +// Open a file, optionally relative to a directory. +// Returns <= -1 on error, file descriptor number on success. +SYSCALL_DEF(16, SYSCALL_FS_OPEN, syscall_fs_open, file_t, char const *path, file_t relative_to, int oflags) + +// Flush and close a file. +SYSCALL_DEF(17, SYSCALL_FS_CLOSE, syscall_fs_close, bool, file_t fd) + +// Read bytes from a file. +// Returns -1 on EOF, <= -2 on error, read count on success. +SYSCALL_DEF(18, SYSCALL_FS_READ, syscall_fs_read, long, file_t fd, void *read_buf, long read_len) + +// Write bytes to a file. +// Returns <= -1 on error, write count on success. +SYSCALL_DEF(19, SYSCALL_FS_WRITE, syscall_fs_write, long, file_t fd, void const *write_buf, long write_len) + +// Read directory entries from a directory handle. +// See `dirent_t` for the format. +// Returns <= -1 on error, read count on success. +SYSCALL_DEF(20, SYSCALL_FS_GETDENTS, syscall_fs_getdents, long, file_t fd, void *read_buf, long read_len) + +// // Rename and/or move a file to another path, optionally relative to one or two directories. +// SYSCALL_DEF_V(21, SYSCALL_FS_RENAME, syscall_fs_rename) + +// // Get file status given file handler or path, optionally following the final symlink. +// SYSCALL_DEF_V(22, SYSCALL_FS_STAT, syscall_fs_stat) + + + +/* ==== MEMORY MANAGEMENT SYSCALLS ==== */ +// Implemented in process/syscall_impl.c + +// Map a new range of memory at an arbitrary virtual address. +// This may round up to a multiple of the page size. +// Alignment may be less than `align` if the kernel doesn't support it. +SYSCALL_DEF(23, SYSCALL_MEM_ALLOC, syscall_mem_alloc, void *, size_t vaddr, size_t size, size_t align, int flags) + +// Get the size of a range of memory previously allocated with `SYSCALL_MEM_ALLOC`. +// Returns 0 if there is no range starting at the given address. +SYSCALL_DEF(24, SYSCALL_MEM_SIZE, syscall_mem_size, size_t, void *address) + +// Unmap a range of memory previously allocated with `SYSCALL_MEM_ALLOC`. +// Returns whether a range of memory was unmapped. +SYSCALL_DEF(25, SYSCALL_MEM_DEALLOC, syscall_mem_dealloc, bool, void *address) + + + +/* ==== LOW-LEVEL HAL SYSCALLS ==== */ +// Implemented in hal/syscall_impl.c + +// Returns the amount of GPIO pins present. +// Cannot produce an error. +SYSCALL_DEF(26, SYSCALL_IO_COUNT, syscall_io_count, int) +// Sets the mode of GPIO pin `pin` to `mode`. +SYSCALL_DEF_V(27, SYSCALL_IO_MODE, syscall_io_mode, badge_err_t *ec, int pin, io_mode_t mode) +// Get the mode of GPIO pin `pin`. +SYSCALL_DEF(28, SYSCALL_IO_GETMODE, syscall_io_getmode, io_mode_t, badge_err_t *ec, int pin) +// Sets the pull resistor behaviour of GPIO pin `pin` to `dir`. +SYSCALL_DEF_V(29, SYSCALL_IO_PULL, syscall_io_pull, badge_err_t *ec, int pin, io_pull_t dir) +// Get the pull resistor behaviour of GPIO pin `pin`. +SYSCALL_DEF(30, SYSCALL_IO_GETPULL, syscall_io_getpull, io_pull_t, badge_err_t *ec, int pin) +// Writes level to GPIO pin pin. +SYSCALL_DEF_V(31, SYSCALL_IO_WRITE, syscall_io_write, badge_err_t *ec, int pin, bool level) +// Reads logic level value from GPIO pin `pin`. +// Returns false on error. +SYSCALL_DEF(32, SYSCALL_IO_READ, syscall_io_read, bool, badge_err_t *ec, int pin) +// Determine whether GPIO `pin` is claimed by a peripheral. +// Returns false on error. +SYSCALL_DEF(33, SYSCALL_IO_IS_PERIPHERAL, syscall_io_is_peripheral, bool, badge_err_t *ec, int pin) + +// Returns the amount of I²C peripherals present. +// Cannot produce an error. +SYSCALL_DEF(34, SYSCALL_I2C_COUNT, syscall_i2c_count, int) +// Initialises I²C peripheral i2c_num in slave mode with SDA pin `sda_pin`, SCL pin `scl_pin` and clock speed/bitrate +// bitrate. When initialised as an I²C master, the modes of the SDA and SCL pins are changed automatically. This +// function may be used again to change the settings on an initialised I²C peripheral in master mode. +SYSCALL_DEF_V(35, SYSCALL_I2C_MASTER_INIT, syscall_i2c_master_init, badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int32_t bitrate) +// De-initialises I²C peripheral i2c_num in master mode. +SYSCALL_DEF_V(36, SYSCALL_I2C_MASTER_DEINIT, syscall_i2c_master_deinit, badge_err_t *ec, int i2c_num) +// Reads len bytes into buffer buf from I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged read bytes. +SYSCALL_DEF(37, SYSCALL_I2C_MASTER_READ_FROM, syscall_i2c_master_read_from, size_t, badge_err_t *ec, int i2c_num, int slave_id, void *buf, size_t len) +// Writes len bytes from buffer buf to I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged written bytes. +SYSCALL_DEF(38, SYSCALL_I2C_MASTER_WRITE_TO, syscall_i2c_master_write_to, size_t, badge_err_t *ec, int i2c_num, int slave_id, void const *buf, size_t len) + +// Returns the amount of SPI peripherals present. +// Cannot produce an error. +SYSCALL_DEF(39, SYSCALL_SPI_COUNT, syscall_spi_count, int) +// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin +// `miso_pin`, SS pin `ss_pin` and clock speed/bitrate bitrate. The modes of the SCLK, MOSI, MISO and SS pins are +// changed automatically. This function may be used again to change the settings on an initialised SPI peripheral in +// controller mode. +SYSCALL_DEF_V(40, SYSCALL_SPI_CONTROLLER_INIT, syscall_spi_controller_init, badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate) +// De-initialises SPI peripheral. +SYSCALL_DEF_V(41, SYSCALL_SPI_DEINIT, syscall_spi_deinit, badge_err_t *ec, int spi_num) +// Reads len bytes into buffer buf from SPI device. +// This function blocks until the entire transaction is completed. +SYSCALL_DEF_V(42, SYSCALL_SPI_CONTROLLER_READ, syscall_spi_controller_read, badge_err_t *ec, int spi_num, void *buf, size_t len) +// Writes len bytes from buffer buf to SPI device. +// This function blocks until the entire transaction is completed. +SYSCALL_DEF_V(43, SYSCALL_SPI_CONTROLLER_WRITE, syscall_spi_controller_write, badge_err_t *ec, int spi_num, void const *buf, size_t len) +// Writes len bytes from buffer buf to SPI device, then reads len bytes into buffer buf from SPI device. +// Write and read happen simultaneously if the full-duplex flag fdx is set. +// This function blocks until the entire transaction is completed. +SYSCALL_DEF_V(44, SYSCALL_SPI_CONTROLLER_TRANSFER, syscall_spi_controller_transfer, badge_err_t *ec, int spi_num, void *buf, size_t len, bool fdx) + + + + +/* ==== SYSTEM MANAGEMENT SYSCALLS ==== */ +// Implemented in main.c + +// Start the shutdown process. +SYSCALL_DEF_V(45, SYSCALL_SYS_SHUTDOWN, syscall_sys_shutdown, bool is_reboot) + + + +/* ==== TEMPORARY SYSCALLS ==== */ +// Implemented in process/syscall_impl.c + +// TEMPORARY: Write one or more characters to the log. +SYSCALL_DEF_V(46, SYSCALL_TEMP_WRITE, syscall_temp_write, char const *message, size_t length) + + + +#undef SYSCALL_DEF +#undef SYSCALL_DEF_V +#undef SYSCALL_DEF_F +#undef SYSCALL_DEF_FV diff --git a/common/syscall_defs.inc b/common/syscall_defs.inc deleted file mode 100644 index 7e278e2..0000000 --- a/common/syscall_defs.inc +++ /dev/null @@ -1,130 +0,0 @@ - -// SPDX-License-Identifier: MIT -// clang-format off - -/* ==== TEMPORARY SYSCALLS ==== */ -// Implemented in syscall.c - -// TEMPORARY: Write one or more characters to the log. -SYSCALL_DEF(0xff00, SYSCALL_TEMP_WRITE, syscall_temp_write, void, char const *message, size_t length) - - - -/* ==== THREAD SYSCALLS ==== */ -// Implemented in process/syscall_impl.c - -// Yield to other threads. -SYSCALL_DEF(0x0100, SYSCALL_THREAD_YIELD, syscall_thread_yield, void) - -// Create a new thread. -SYSCALL_DEF(0x0101, SYSCALL_THREAD_CREATE, syscall_thread_create, bool, void *entry, void *arg, int priority) - -// Suspend a thread; it will not run again until resumed. -SYSCALL_DEF(0x0102, SYSCALL_THREAD_SUSPEND, syscall_thread_suspend, bool, tid_t thread) - -// Resume a thread; this does nothing if it is already running. -SYSCALL_DEF(0x0103, SYSCALL_THREAD_RESUME, syscall_thread_resume, bool, tid_t thread) - -// Detach a thread; the thread will be destroyed as soon as it exits. -SYSCALL_DEF(0x0104, SYSCALL_THREAD_DETACH, syscall_thread_detach, bool, tid_t thread) - -// Destroy a thread; it will be stopped and its resources released. -SYSCALL_DEF(0x0105, SYSCALL_THREAD_DESTROY, syscall_thread_destroy, bool, tid_t thread) - -// Exit the current thread; exit code can be read unless destroyed or detached. -SYSCALL_DEF(0x0106, SYSCALL_THREAD_EXIT, syscall_thread_exit, void, int code) - - - -/* ==== PROCESS MANAGEMENT SYSCALLS ==== */ -// Implemented in process/syscall_impl.c - -// Exit the process; exit code can be read by parent process. -SYSCALL_DEF(0x0200, SYSCALL_PROC_EXIT, syscall_proc_exit, void, int code) - -// Get the command-line arguments (i.e. argc+argv) of the current process. -// If memory is large enough, a NULL-terminated argv array of C-string pointers and their data is stored in `memory`. -// The function returns how many bytes would be needed to store the structure. -// If the memory was not large enough, it it not modified. -SYSCALL_DEF(0x0201, SYSCALL_PROC_GETARGS, syscall_proc_getargs, size_t, size_t cap, void *memory) - -// Create a "pre-start" child process that inherits this process' file descriptors and environment variables. -// The child process is created in a halted state and it is killed if the parent exits before the child is resumed. -// Returns process ID of new child on success, or a (negative) errno on failure. -SYSCALL_DEF(0x0202, SYSCALL_PROC_PCREATE, syscall_proc_pcreate, int, char const *binary, int argc, char const *const *argv) - -// Destroy a "pre-start" child process. -// Usually used in case of errors. -SYSCALL_DEF(0x0203, SYSCALL_PROC_PDESTROY, syscall_proc_pdestroy, bool, int child) - -// Starts a "pre-start" child process, thereby converting it into a running child process. -SYSCALL_DEF(0x0204, SYSCALL_PROC_PSTART, syscall_proc_pstart, bool, int child) - -// Set the signal handler for a specific signal number. -SYSCALL_DEF(0x0205, SYSCALL_PROC_SIGHANDLER, syscall_proc_sighandler, void *, int signum, void *newhandler) - -// Return from a signal handler. -SYSCALL_DEF(0x0206, SYSCALL_PROC_SIGRET, syscall_proc_sigret, void) - -// Get child process status update. -SYSCALL_DEF(0x0207, SYSCALL_PROC_WAITPID, syscall_proc_waitpid, int, int pid, int *wstatus, int options) - - -/* ==== FILESYSTEM SYSCALLS ==== */ -// Implemented in filesystem/syscall_impl.c - -// Open a file, optionally relative to a directory. -// Returns <= -1 on error, file descriptor number on success. -SYSCALL_DEF(0x0300, SYSCALL_FS_OPEN, syscall_fs_open, file_t, char const *path, file_t relative_to, int oflags) - -// Flush and close a file. -SYSCALL_DEF(0x0301, SYSCALL_FS_CLOSE, syscall_fs_close, bool, file_t fd) - -// Read bytes from a file. -// Returns -1 on EOF, <= -2 on error, read count on success. -SYSCALL_DEF(0x0302, SYSCALL_FS_READ, syscall_fs_read, long, file_t fd, void *read_buf, long read_len) - -// Write bytes to a file. -// Returns <= -1 on error, write count on success. -SYSCALL_DEF(0x0303, SYSCALL_FS_WRITE, syscall_fs_write, long, file_t fd, void const *write_buf, long write_len) - -// Read directory entries from a directory handle. -// See `dirent_t` for the format. -// Returns <= -1 on error, read count on success. -SYSCALL_DEF(0x0304, SYSCALL_FS_GETDENTS, syscall_fs_getdents, long, file_t fd, void *read_buf, long read_len) - -// RESERVED FOR: Rename and/or move a file to another path, optionally relative to one or two directories. -SYSCALL_DEF(0x0305, SYSCALL_FS_RENAME, syscall_fs_rename, void) - -// RESERVED FOR: Get file status given file handler or path, optionally following the final symlink. -SYSCALL_DEF(0x0306, SYSCALL_FS_STAT, syscall_fs_stat, void) - - - -/* ==== MEMORY MANAGEMENT SYSCALLS ==== */ -// Implemented in process/syscall_impl.c - -// Map a new range of memory at an arbitrary virtual address. -// This may round up to a multiple of the page size. -// Alignment may be less than `align` if the kernel doesn't support it. -SYSCALL_DEF(0x0400, SYSCALL_MEM_ALLOC, syscall_mem_alloc, void *, size_t vaddr, size_t size, size_t align, int flags) - -// Get the size of a range of memory previously allocated with `SYSCALL_MEM_ALLOC`. -// Returns 0 if there is no range starting at the given address. -SYSCALL_DEF(0x0401, SYSCALL_MEM_SIZE, syscall_mem_size, size_t, void *address) - -// Unmap a range of memory previously allocated with `SYSCALL_MEM_ALLOC`. -// Returns whether a range of memory was unmapped. -SYSCALL_DEF(0x0402, SYSCALL_MEM_DEALLOC, syscall_mem_dealloc, bool, void *address) - - - -/* ==== SYSTEM MANAGEMENT SYSCALLS ==== */ -// Implemented in main.c - -// Start the shutdown process. -SYSCALL_DEF(0x0500, SYSCALL_SYS_SHUTDOWN, syscall_sys_shutdown, void, bool is_reboot) - - - -#undef SYSCALL_DEF diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt new file mode 100644 index 0000000..d3745b2 --- /dev/null +++ b/files/CMakeLists.txt @@ -0,0 +1,53 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +set(CMAKE_EXPORT_COMPILE_COMMANDS true) +include(../common/compiler.cmake) + +if("${BADGEROS_PORT}" STREQUAL "esp32c6") + set(target_arch rv32imac_zicsr_zifencei) + set(target_abi ilp32) +elseif("${BADGEROS_PORT}" STREQUAL "esp32p4") + set(target_arch rv32imafc_zicsr_zifencei) + set(target_abi ilp32) +endif() + +set(badge_cflags + -ffreestanding + -fpie + -march=${target_arch} # Selects the target CPU. + -mabi=${target_abi} # Selects target ABI + -nodefaultlibs -nostdlib # Do not link any default libraries like libgcc or libc. + -O2 # Optimize the code. + -Werror=return-type # Error when a function doesn't return a value, but declares to do so. + -Werror=implicit-fallthrough + -Wall -Wextra # Ramp up warning level. + -std=gnu11 # We use the C11 standard + -DBADGEROS # Tell the code we're building for the userspace + -DBADGEROS_PORT_${BADGEROS_PORT} + -DBADGEROS_PORT="${BADGEROS_PORT}" + -fno-omit-frame-pointer # Always use frame pointer + -fno-stack-protector + -fno-exceptions +) + +project(root C ASM) + +set(badge_include + ${CMAKE_CURRENT_LIST_DIR}/../common/include + ${CMAKE_CURRENT_LIST_DIR}/../common/badgelib +) +set(badge_libs crt) +macro(badgeros_executable exec installdir) + add_executable(${exec}) + target_compile_options(${exec} PRIVATE ${badge_cflags} -ffunction-sections) + target_link_options(${exec} PRIVATE ${badge_cflags} -Wl,--gc-sections -nostartfiles) + target_include_directories(${exec} PRIVATE ${badge_include}) + target_link_libraries(${exec} PRIVATE ${badge_libs}) + install(TARGETS ${exec} RUNTIME DESTINATION ${installdir}) +endmacro() + +add_subdirectory(lib) +add_subdirectory(sbin) diff --git a/files/Makefile b/files/Makefile index 1e13b9d..2b38114 100644 --- a/files/Makefile +++ b/files/Makefile @@ -3,24 +3,19 @@ MAKEFLAGS += --silent SHELL := /usr/bin/env bash +BUILDDIR ?= $(shell pwd)/build OUTPUT ?= $(shell pwd)/root -.PHONY: all clean-all clean build +.PHONY: all clean build all: build build: - $(MAKE) -C init - $(MAKE) -C test + mkdir -p '$(BUILDDIR)' mkdir -p '$(OUTPUT)' - mkdir -p '$(OUTPUT)/sbin' - mkdir -p '$(OUTPUT)/etc' - cp init/app/app.elf '$(OUTPUT)/sbin/init' - cp test/app/app.elf '$(OUTPUT)/sbin/test' - echo -e 'Hello, World!\nCompiled at $(shell date)' > $(OUTPUT)/etc/motd - -clean-all: clean - $(MAKE) -C init clean-all + cmake -B '$(BUILDDIR)' + cmake --build '$(BUILDDIR)' + cmake --install '$(BUILDDIR)' --prefix '$(OUTPUT)' clean: - rm -rf '$(OUTPUT)' + rm -rf '$(BUILDDIR)' '$(OUTPUT)' diff --git a/files/init/CMakeLists.txt b/files/bak/init/CMakeLists.txt similarity index 96% rename from files/init/CMakeLists.txt rename to files/bak/init/CMakeLists.txt index eed219f..7ad3a53 100644 --- a/files/init/CMakeLists.txt +++ b/files/bak/init/CMakeLists.txt @@ -66,7 +66,8 @@ add_executable(${target} ) target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src - ${CMAKE_CURRENT_LIST_DIR}/../../common + ${CMAKE_CURRENT_LIST_DIR}/../../common/badgelib + ${CMAKE_CURRENT_LIST_DIR}/../../common/include ) # Declare which files are installed to the output directory: diff --git a/files/init/Makefile b/files/bak/init/Makefile similarity index 100% rename from files/init/Makefile rename to files/bak/init/Makefile diff --git a/files/init/src/main.c b/files/bak/init/src/main.c similarity index 100% rename from files/init/src/main.c rename to files/bak/init/src/main.c diff --git a/files/init/src/start.S b/files/bak/init/src/start.S similarity index 100% rename from files/init/src/start.S rename to files/bak/init/src/start.S diff --git a/files/init/src/syscall.c b/files/bak/init/src/syscall.c similarity index 100% rename from files/init/src/syscall.c rename to files/bak/init/src/syscall.c diff --git a/files/test/CMakeLists.txt b/files/bak/test/CMakeLists.txt similarity index 100% rename from files/test/CMakeLists.txt rename to files/bak/test/CMakeLists.txt diff --git a/files/test/Makefile b/files/bak/test/Makefile similarity index 100% rename from files/test/Makefile rename to files/bak/test/Makefile diff --git a/files/test/src/main.c b/files/bak/test/src/main.c similarity index 100% rename from files/test/src/main.c rename to files/bak/test/src/main.c diff --git a/files/test/src/start.S b/files/bak/test/src/start.S similarity index 100% rename from files/test/src/start.S rename to files/bak/test/src/start.S diff --git a/files/test/src/syscall.c b/files/bak/test/src/syscall.c similarity index 100% rename from files/test/src/syscall.c rename to files/bak/test/src/syscall.c diff --git a/files/lib/CMakeLists.txt b/files/lib/CMakeLists.txt new file mode 100644 index 0000000..7a7efbb --- /dev/null +++ b/files/lib/CMakeLists.txt @@ -0,0 +1,8 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +add_subdirectory(crt) +add_subdirectory(syscall) +add_subdirectory(badge) diff --git a/files/lib/badge/CMakeLists.txt b/files/lib/badge/CMakeLists.txt new file mode 100644 index 0000000..d4c9323 --- /dev/null +++ b/files/lib/badge/CMakeLists.txt @@ -0,0 +1,4 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) diff --git a/files/lib/crt/CMakeLists.txt b/files/lib/crt/CMakeLists.txt new file mode 100644 index 0000000..8eea42f --- /dev/null +++ b/files/lib/crt/CMakeLists.txt @@ -0,0 +1,10 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +add_library(crt start.S) +target_compile_options(crt PRIVATE ${badge_cflags} -ffunction-sections) +target_link_options(crt PRIVATE ${badge_cflags} -Wl,--gc-sections -nostartfiles) +target_include_directories(crt PRIVATE ${badge_include}) +target_link_libraries(crt PUBLIC syscall) diff --git a/files/lib/crt/start.S b/files/lib/crt/start.S new file mode 100644 index 0000000..bf56c2a --- /dev/null +++ b/files/lib/crt/start.S @@ -0,0 +1,47 @@ + +# SPDX-License-Identifier: MIT + +#include "syscall.h" + + .global __global_pointer$ + .global main + + + + .global _start + .text + .p2align 1 +_start: + # Set stack and global pointer. + .option push + .option norelax + la sp, stack_top + la gp, __global_pointer$ + .option pop + + # Set signal handler return trampoline. + li a0, 0 + la a1, sigret_trampoline + jal syscall_proc_sighandler + + # TODO: argc and argv + + # Jump to main function + jal main + + # Exit the process if main returns + li a7, SYSCALL_PROC_EXIT + ecall + + + +sigret_trampoline: + j syscall_proc_sigret + + + + # Main stack. + .section ".bss" +stack_bottom: + .zero 1024 +stack_top: diff --git a/files/lib/syscall/CMakeLists.txt b/files/lib/syscall/CMakeLists.txt new file mode 100644 index 0000000..43cd20b --- /dev/null +++ b/files/lib/syscall/CMakeLists.txt @@ -0,0 +1,14 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +add_library(syscall + src/gpio.c + src/i2c.c + src/spi.c + src/syscall.c +) +target_compile_options(syscall PRIVATE ${badge_cflags} -ffunction-sections) +target_link_options(syscall PRIVATE ${badge_cflags} -Wl,--gc-sections -nostartfiles) +target_include_directories(syscall PRIVATE ${badge_include}) diff --git a/files/lib/syscall/src/gpio.c b/files/lib/syscall/src/gpio.c new file mode 100644 index 0000000..19bd1b8 --- /dev/null +++ b/files/lib/syscall/src/gpio.c @@ -0,0 +1,49 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/gpio.h" + +#include "syscall.h" + +// Returns the amount of GPIO pins present. +// Cannot produce an error. +int io_count() { + return syscall_io_count(); +} + +// Sets the mode of GPIO pin `pin` to `mode`. +void io_mode(badge_err_t *ec, int pin, io_mode_t mode) { + syscall_io_mode(ec, pin, mode); +} + +// Get the mode of GPIO pin `pin`. +io_mode_t io_getmode(badge_err_t *ec, int pin) { + return syscall_io_getmode(ec, pin); +} + +// Sets the pull resistor behaviour of GPIO pin `pin` to `dir`. +void io_pull(badge_err_t *ec, int pin, io_pull_t dir) { + syscall_io_pull(ec, pin, dir); +} + +// Get the pull resistor behaviour of GPIO pin `pin`. +io_pull_t io_getpull(badge_err_t *ec, int pin) { + return syscall_io_getpull(ec, pin); +} + +// Writes level to GPIO pin pin. +void io_write(badge_err_t *ec, int pin, bool level) { + syscall_io_write(ec, pin, level); +} + +// Reads logic level value from GPIO pin `pin`. +// Returns false on error. +bool io_read(badge_err_t *ec, int pin) { + return syscall_io_read(ec, pin); +} + +// Determine whether GPIO `pin` is claimed by a peripheral. +// Returns false on error. +bool io_is_peripheral(badge_err_t *ec, int pin) { + return syscall_io_is_peripheral(ec, pin); +} diff --git a/files/lib/syscall/src/i2c.c b/files/lib/syscall/src/i2c.c new file mode 100644 index 0000000..8d1db41 --- /dev/null +++ b/files/lib/syscall/src/i2c.c @@ -0,0 +1,36 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/i2c.h" + +#include "syscall.h" + +// Returns the amount of I²C peripherals present. +// Cannot produce an error. +int i2c_count() { + return syscall_i2c_count(); +} + +// Initialises I²C peripheral i2c_num in slave mode with SDA pin `sda_pin`, SCL pin `scl_pin` and clock speed/bitrate +// bitrate. When initialised as an I²C master, the modes of the SDA and SCL pins are changed automatically. This +// function may be used again to change the settings on an initialised I²C peripheral in master mode. +void i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int32_t bitrate) { + return syscall_i2c_master_init(ec, i2c_num, sda_pin, scl_pin, bitrate); +} + +// De-initialises I²C peripheral i2c_num in master mode. +void i2c_master_deinit(badge_err_t *ec, int i2c_num) { + return syscall_i2c_master_deinit(ec, i2c_num); +} + +// Reads len bytes into buffer buf from I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged read bytes. +size_t i2c_master_read_from(badge_err_t *ec, int i2c_num, int slave_id, void *buf, size_t len) { + return syscall_i2c_master_read_from(ec, i2c_num, slave_id, buf, len); +} + +// Writes len bytes from buffer buf to I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged written bytes. +size_t i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void const *buf, size_t len) { + return syscall_i2c_master_write_to(ec, i2c_num, slave_id, buf, len); +} diff --git a/files/lib/syscall/src/spi.c b/files/lib/syscall/src/spi.c new file mode 100644 index 0000000..8c500c9 --- /dev/null +++ b/files/lib/syscall/src/spi.c @@ -0,0 +1,46 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/spi.h" + +#include "syscall.h" + +// Returns the amount of SPI peripherals present. +// Cannot produce an error. +int spi_count() { + return syscall_spi_count(); +} + +// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin +// `miso_pin`, SS pin `ss_pin` and clock speed/bitrate bitrate. The modes of the SCLK, MOSI, MISO and SS pins are +// changed automatically. This function may be used again to change the settings on an initialised SPI peripheral in +// controller mode. +void spi_controller_init( + badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate +) { + syscall_spi_controller_init(ec, spi_num, sclk_pin, mosi_pin, miso_pin, ss_pin, bitrate); +} + +// De-initialises SPI peripheral. +void spi_deinit(badge_err_t *ec, int spi_num) { + syscall_spi_deinit(ec, spi_num); +} + +// Reads len bytes into buffer buf from SPI device. +// This function blocks until the entire transaction is completed. +void spi_controller_read(badge_err_t *ec, int spi_num, void *buf, size_t len) { + syscall_spi_controller_read(ec, spi_num, buf, len); +} + +// Writes len bytes from buffer buf to SPI device. +// This function blocks until the entire transaction is completed. +void spi_controller_write(badge_err_t *ec, int spi_num, void const *buf, size_t len) { + syscall_spi_controller_write(ec, spi_num, buf, len); +} + +// Writes len bytes from buffer buf to SPI device, then reads len bytes into buffer buf from SPI device. +// Write and read happen simultaneously if the full-duplex flag fdx is set. +// This function blocks until the entire transaction is completed. +void spi_controller_transfer(badge_err_t *ec, int spi_num, void *buf, size_t len, bool fdx) { + syscall_spi_controller_transfer(ec, spi_num, buf, len, fdx); +} diff --git a/files/lib/syscall/src/syscall.c b/files/lib/syscall/src/syscall.c new file mode 100644 index 0000000..99c298c --- /dev/null +++ b/files/lib/syscall/src/syscall.c @@ -0,0 +1,15 @@ + +// SPDX-License-Identifier: MIT + +#include "syscall.h" + +// These syscalls *do* actually take parameters, but GCC doesn't realise this. +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#define SYSCALL_DEF(num, enum, name, returns, ...) \ + returns name(__VA_ARGS__) __attribute__((naked)); \ + returns name(__VA_ARGS__) { \ + asm("li a7, " #num "; ecall; ret"); \ + } + +#include "syscall_defs.inc" diff --git a/files/sbin/CMakeLists.txt b/files/sbin/CMakeLists.txt new file mode 100644 index 0000000..ddb103d --- /dev/null +++ b/files/sbin/CMakeLists.txt @@ -0,0 +1,6 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +add_subdirectory(init) diff --git a/files/sbin/init/CMakeLists.txt b/files/sbin/init/CMakeLists.txt new file mode 100644 index 0000000..39a4e9d --- /dev/null +++ b/files/sbin/init/CMakeLists.txt @@ -0,0 +1,9 @@ + +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10.0) + +badgeros_executable(init sbin) +target_sources(init PRIVATE + main.c +) diff --git a/files/sbin/init/main.c b/files/sbin/init/main.c new file mode 100644 index 0000000..448afd7 --- /dev/null +++ b/files/sbin/init/main.c @@ -0,0 +1,95 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/i2c.h" +#include "syscall.h" + +#define SDA_PIN 6 +#define SCL_PIN 7 +#define CH32_ADDR 0x42 + +#define I2C_REG_FW_VERSION_0 0 // LSB +#define I2C_REG_FW_VERSION_1 1 // MSB +#define I2C_REG_RESERVED_0 2 +#define I2C_REG_RESERVED_1 3 +#define I2C_REG_LED_0 4 // LSB +#define I2C_REG_LED_1 5 +#define I2C_REG_LED_2 6 +#define I2C_REG_LED_3 7 // MSB +#define I2C_REG_BTN_0 8 // Button 0 +#define I2C_REG_BTN_1 9 // Button 1 +#define I2C_REG_BTN_2 10 // Button 2 +#define I2C_REG_BTN_3 11 // Button 3 +#define I2C_REG_BTN_4 12 // Button 4 + +uint8_t read_reg(uint8_t regno) { + badge_err_t ec = {0}; + i2c_master_write_to(&ec, 0, CH32_ADDR, ®no, 1); + uint8_t ret = 0; + i2c_master_read_from(&ec, 0, CH32_ADDR, &ret, 1); + return ret; +} + +size_t strlen(char const *cstr) { + char const *pre = cstr; + while (*cstr) cstr++; + return cstr - pre; +} + +void print(char const *cstr) { + syscall_temp_write(cstr, strlen(cstr)); +} + +char const hextab[] = "0123456789ABCDEF"; + +int main() { + badge_err_t ec = {0}; + print("Hi, Ther."); + // syscall_sys_shutdown(false); + // return 420; + + // Set up I2C to the CH32V003. + i2c_master_init(&ec, 0, SDA_PIN, SCL_PIN, 100000); + i2c_master_write_to(&ec, 0, CH32_ADDR, "\x00", 1); + i2c_master_write_to(&ec, 0, CH32_ADDR, "\x00", 1); + uint8_t tmp; + // i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1); + // i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1); + // i2c_master_read_from(&ec, 0, CH32_ADDR, &tmp, 1); + // i2c_master_write_to(&ec, 0, CH32_ADDR, "\x04\xff\xff", 3); + // syscall_sys_shutdown(false); + // return 69; + + // Read coproc FW ver. + uint16_t fwv = read_reg(I2C_REG_FW_VERSION_0) | (read_reg(I2C_REG_FW_VERSION_1) << 8); + char buf[4]; + buf[0] = hextab[(fwv >> 12) & 15]; + buf[1] = hextab[(fwv >> 8) & 15]; + buf[2] = hextab[(fwv >> 4) & 15]; + buf[3] = hextab[(fwv >> 0) & 15]; + print("CH32 version: 0x"); + syscall_temp_write(buf, 4); + print("\n"); + + // Poll inputs until one of the buttons is pressed, then exit. + // while (true) { + if (read_reg(I2C_REG_BTN_0)) { + print("BTN0 triggered\n"); + } + if (read_reg(I2C_REG_BTN_1)) { + print("BTN1 triggered\n"); + } + if (read_reg(I2C_REG_BTN_2)) { + print("BTN2 triggered\n"); + } + if (read_reg(I2C_REG_BTN_3)) { + print("BTN3 triggered\n"); + } + if (read_reg(I2C_REG_BTN_4)) { + print("BTN4 triggered\n"); + } + // } + + syscall_sys_shutdown(false); + return 0; +} diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 3a0fa80..32f4a6b 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -5,44 +5,21 @@ cmake_minimum_required(VERSION 3.10.0) set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") -# The target platform -if(NOT DEFINED ENV{BADGEROS_PORT}) - set(BADGEROS_PORT esp32c6) -else() - set(BADGEROS_PORT $ENV{BADGEROS_PORT}) -endif() - # Set the RAMFS root if(NOT DEFINED BADGER_RAMFS_ROOT) set(BADGER_RAMFS_ROOT ${CMAKE_CURRENT_LIST_DIR}/root) endif() # Set the C compiler -if(DEFINED CMAKE_C_COMPILER) - message("Using compiler '${CMAKE_C_COMPILER}' from environment") -elseif(DEFINED ENV{CMAKE_C_COMPILER}) - set(CMAKE_C_COMPILER $ENV{CMAKE_C_COMPILER}) - message("Using compiler '${CMAKE_C_COMPILER}' from environment") -else() - find_program(CMAKE_C_COMPILER NAMES riscv32-badgeros-linux-gnu-gcc riscv32-unknown-linux-gnu-gcc riscv32-linux-gnu-gcc riscv64-unknown-linux-gnu-gcc riscv64-linux-gnu-gcc REQUIRED) - message("Detected RISC-V C compiler as '${CMAKE_C_COMPILER}'") -endif() - -# Determine the compiler prefix -get_filename_component(compiler_name "${CMAKE_C_COMPILER}" NAME) -string(REGEX MATCH "^([A-Za-z0-9_]+\-)*" BADGER_COMPILER_PREFIX "${compiler_name}") -find_program(BADGER_OBJCOPY NAMES "${BADGER_COMPILER_PREFIX}objcopy" REQUIRED) -find_program(BADGER_OBJDUMP NAMES "${BADGER_COMPILER_PREFIX}objdump" REQUIRED) +include(../common/compiler.cmake) # Include port-specific. include(port/${BADGEROS_PORT}/CMakeLists.txt) include(cpu/riscv/CMakeLists.txt) -# LTO is disabled due to GCC bugs inserting calls to memcpy everywhere set(common_compiler_flags -ffreestanding # We do not compile against an OS. -static -fno-pic # Disable PIC - -fno-exceptions -march=${target_arch} # Selects the target CPU. -mabi=${target_abi} # Selects target ABI -nodefaultlibs -nostdlib # Do not link any default libraries like libgcc or libc. @@ -74,7 +51,7 @@ endif() # we must pass the same options to GCC and LD when using LTO, as the linker will actually do the codegen add_compile_options(${common_compiler_flags} ${cpu_flags} ${port_flags}) -add_link_options(${common_compiler_flags} ${cpu_link} ${port_link} -nostartfiles) +add_link_options(${common_compiler_flags} ${cpu_link} ${port_link} -Wl,--gc-sections -nostartfiles) # For IDE users. set(CMAKE_EXPORT_COMPILE_COMMANDS true) @@ -102,16 +79,19 @@ add_executable(${target} # ${CMAKE_CURRENT_LIST_DIR}/src/filesystem/vfs_fat.c ${CMAKE_CURRENT_LIST_DIR}/src/filesystem/vfs_ramfs.c ${CMAKE_CURRENT_LIST_DIR}/src/filesystem/vfs_internal.c - ${CMAKE_CURRENT_LIST_DIR}/src/loading/kbelfx.c + ${CMAKE_CURRENT_LIST_DIR}/src/hal/syscall_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/malloc/malloc.c + ${CMAKE_CURRENT_LIST_DIR}/src/malloc/static-buddy.c + ${CMAKE_CURRENT_LIST_DIR}/src/malloc/slab-alloc.c + ${CMAKE_CURRENT_LIST_DIR}/src/process/kbelfx.c ${CMAKE_CURRENT_LIST_DIR}/src/process/process.c ${CMAKE_CURRENT_LIST_DIR}/src/process/sighandler.c ${CMAKE_CURRENT_LIST_DIR}/src/process/syscall_impl.c + ${CMAKE_CURRENT_LIST_DIR}/src/process/syscall_util.c + ${CMAKE_CURRENT_LIST_DIR}/src/scheduler/scheduler.c + ${CMAKE_CURRENT_LIST_DIR}/src/scheduler/syscall_impl.c ${CMAKE_CURRENT_LIST_DIR}/src/housekeeping.c ${CMAKE_CURRENT_LIST_DIR}/src/main.c - ${CMAKE_CURRENT_LIST_DIR}/src/malloc/malloc.c - ${CMAKE_CURRENT_LIST_DIR}/src/malloc/static-buddy.c - ${CMAKE_CURRENT_LIST_DIR}/src/malloc/slab-alloc.c - ${CMAKE_CURRENT_LIST_DIR}/src/scheduler.c ${CMAKE_CURRENT_LIST_DIR}/src/syscall.c ${cpu_src} ${port_src} @@ -120,19 +100,22 @@ target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/src/malloc ${CMAKE_CURRENT_LIST_DIR}/include/badgelib - ${CMAKE_CURRENT_LIST_DIR}/../common + ${CMAKE_CURRENT_LIST_DIR}/../common/include + ${CMAKE_CURRENT_LIST_DIR}/../common/badgelib ${cpu_include} ${port_include} ) # Add libraries. -add_subdirectory(../lib/kbelf ${CMAKE_BINARY_DIR}/kbelf) +add_subdirectory(lib/kbelf) target_compile_options(kbelf PRIVATE -include ${CMAKE_CURRENT_LIST_DIR}/include/loading/kbelf_pre.h ) target_include_directories(kbelf PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include ${CMAKE_CURRENT_LIST_DIR}/include/badgelib + ${CMAKE_CURRENT_LIST_DIR}/../common/include + ${CMAKE_CURRENT_LIST_DIR}/../common/badgelib ${cpu_include} ${port_include} ) diff --git a/kernel/Makefile b/kernel/Makefile index b47358d..49360ce 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,7 +10,7 @@ BUILDDIR ?= build BADGER_RAMFS_ROOT ?= ../files/root BADGEROS_PORT ?= esp32c6 -.PHONY: all clean-tools clean configure build flash monitor test clang-format-check clang-tidy-check openocd gdb +.PHONY: all clean configure build flash monitor clang-format-check clang-tidy-check openocd gdb all: build flash monitor @@ -42,7 +42,6 @@ openocd: gdb: riscv32-unknown-elf-gdb -x port/$(BADGEROS_PORT)/gdbinit build/badger-os.elf -clean-all: clean clean: rm -rf "$(BUILDDIR)" diff --git a/kernel/cpu/riscv/CMakeLists.txt b/kernel/cpu/riscv/CMakeLists.txt index 22fb6cf..7f244f8 100644 --- a/kernel/cpu/riscv/CMakeLists.txt +++ b/kernel/cpu/riscv/CMakeLists.txt @@ -8,6 +8,7 @@ set(cpu_src ${CMAKE_CURRENT_LIST_DIR}/src/isr.S ${CMAKE_CURRENT_LIST_DIR}/src/isr_ctx.S ${CMAKE_CURRENT_LIST_DIR}/src/isr_noexc.S + ${CMAKE_CURRENT_LIST_DIR}/src/syscall.S ${CMAKE_CURRENT_LIST_DIR}/src/backtrace.c ${CMAKE_CURRENT_LIST_DIR}/src/isr.c diff --git a/kernel/cpu/riscv/include/cpu/isr.h b/kernel/cpu/riscv/include/cpu/isr.h index 57f0607..29cb411 100644 --- a/kernel/cpu/riscv/include/cpu/isr.h +++ b/kernel/cpu/riscv/include/cpu/isr.h @@ -32,17 +32,12 @@ extern uint32_t riscv_interrupt_vector_table[32]; // Callback from ASM to platform-specific interrupt handler. extern void riscv_interrupt_handler(); -// Signature for system call handler. -#define SYSCALL_HANDLER_SIGNATURE \ - void syscall_handler(long a0, long a1, long a2, long a3, long a4, long a5, long a6, long sysnum) -// Suppress unused arguments warning for syscall implementation. -#define SYSCALL_HANDLER_IGNORE_UNUSED (void)a0, (void)a1, (void)a2, (void)a3, (void)a4, (void)a5, (void)a6, (void)sysnum -// Callback from ASM to syscall implementation. -extern SYSCALL_HANDLER_SIGNATURE; +// ASM system call wrapper function. +extern void riscv_syscall_wrapper(); // Callback from ASM on non-syscall trap. -extern void riscv_trap_handler(); +extern void riscv_trap_handler(); // Return a value from the syscall handler. -extern void syscall_return(long long value) __attribute__((noreturn)); +extern void syscall_return(long long value) __attribute__((noreturn)); // Disable interrupts and return whether they were enabled. static inline bool isr_global_disable() { diff --git a/kernel/cpu/riscv/src/isr.c b/kernel/cpu/riscv/src/isr.c index 8015b13..1bbd930 100644 --- a/kernel/cpu/riscv/src/isr.c +++ b/kernel/cpu/riscv/src/isr.c @@ -79,7 +79,7 @@ void riscv_trap_handler() { case RISCV_TRAP_U_ECALL: // ECALL from U-mode goes to system call handler. - sched_raise_from_isr(kctx->thread, true, syscall_handler); + sched_raise_from_isr(kctx->thread, true, riscv_syscall_wrapper); isr_ctx_swap(kctx); trap_depth--; return; diff --git a/kernel/cpu/riscv/src/panic.c b/kernel/cpu/riscv/src/panic.c index 074b298..8d9f560 100644 --- a/kernel/cpu/riscv/src/panic.c +++ b/kernel/cpu/riscv/src/panic.c @@ -3,16 +3,22 @@ #include "cpu/panic.h" +#include "backtrace.h" #include "interrupt.h" #include "isr_ctx.h" #include "log.h" #include "rawprint.h" +void abort() { + panic_abort(); +} + // Call this function when and only when the kernel has encountered a fatal error. // Prints register dump for current kernel context and jumps to `panic_poweroff`. void panic_abort() { irq_enable(false); logkf_from_isr(LOG_FATAL, "`panic_abort()` called!"); + backtrace(); kernel_cur_regs_dump(); panic_poweroff(); } diff --git a/kernel/cpu/riscv/src/syscall.S b/kernel/cpu/riscv/src/syscall.S new file mode 100644 index 0000000..80a26c3 --- /dev/null +++ b/kernel/cpu/riscv/src/syscall.S @@ -0,0 +1,47 @@ + +# SPDX-License-Identifier: MIT + + + + .text + .align 2 + .global riscv_syscall_wrapper + # Called directly from `sched_raise_from_isr`; overwrites callee-save registers. +riscv_syscall_wrapper: + # Save arguments. + mv s1, a0 + mv s2, a1 + mv s3, a2 + mv s4, a3 + mv s5, a4 + mv s6, a5 + mv s7, a6 + # Get syscall information. + mv a0, a7 + jal syscall_info + # If it doesn't exist, go to sigsys handler. + bnez a0, .gotosys + j proc_sigsys_handler + # Run the system call. +.gotosys: + mv s8, a0 + mv s9, a1 + mv a0, s1 + mv a1, s2 + mv a2, s3 + mv a3, s4 + mv a4, s5 + mv a5, s6 + mv a6, s7 + jalr s8 + # Truncate return value. + andi t0, s9, 255 + li t1, __riscv_xlen/8 + bgt t0, t1, .args2 + bnez t0, .args1 + li a0, 0 +.args1: + li a1, 0 +.args2: + # Return from system call. + j syscall_return diff --git a/kernel/include/interrupt.h b/kernel/include/interrupt.h index 8ea38d8..b444883 100644 --- a/kernel/include/interrupt.h +++ b/kernel/include/interrupt.h @@ -25,6 +25,8 @@ void irq_ch_enable(int int_irq, bool enable); bool irq_ch_enabled(int int_irq); // Query whether an internal interrupt is pending. bool irq_ch_pending(int int_irq); +// Query whether an external interrupt is pending. +bool irq_ch_ext_pending(int ext_irq); // Set the interrupt service routine for an interrupt on this CPU. void irq_ch_set_isr(int int_irq, isr_t isr); diff --git a/kernel/include/process/process.h b/kernel/include/process/process.h index a06c074..f81df89 100644 --- a/kernel/include/process/process.h +++ b/kernel/include/process/process.h @@ -29,6 +29,8 @@ typedef int pid_t; // Create a new, empty process. pid_t proc_create(badge_err_t *ec, pid_t parent, char const *binary, int argc, char const *const *argv); +// Delete a process only if it hasn't been started yet. +bool proc_delete_prestart(pid_t pid); // Delete a process and release any resources it had. void proc_delete(pid_t pid); // Get the process' flags. diff --git a/kernel/include/syscall_util.h b/kernel/include/syscall_util.h new file mode 100644 index 0000000..c0fed7f --- /dev/null +++ b/kernel/include/syscall_util.h @@ -0,0 +1,28 @@ + +// SPDX-License-Identifier: MIT + +#pragma once + +#include "memprotect.h" +#include "syscall.h" + +#include +#include +#include + + + +// Assert that a condition is true, or raise SIGSYS and don't return. +void sigsys_assert(bool condition); +// Assert that a condition is true, or raise SIGSEGV and don't return. +void sigsegv_assert(bool condition); +// Checks whether the process has permission for a range of memory. +bool sysutil_memperm(void const *ptr, size_t len, uint32_t flags); +// If the process does not have access, raise SIGSEGV and don't return. +void sysutil_memassert(void const *ptr, size_t len, uint32_t flags); +// Assert the process can read memory, or raise SIGSEGV and don't return. +#define sysutil_memassert_r(ptr, len) sysutil_memassert(ptr, len, MEMPROTECT_FLAG_R) +// Assert the process can read/write memory, or raise SIGSEGV and don't return. +#define sysutil_memassert_rw(ptr, len) sysutil_memassert(ptr, len, MEMPROTECT_FLAG_RW) +// Assert the process can execute memory, or raise SIGSEGV and don't return. +#define sysutil_memassert_x(ptr, len) sysutil_memassert(ptr, len, MEMPROTECT_FLAG_X) diff --git a/lib/kbelf b/kernel/lib/kbelf similarity index 100% rename from lib/kbelf rename to kernel/lib/kbelf diff --git a/kernel/port/esp32c6/CMakeLists.txt b/kernel/port/esp32c6/CMakeLists.txt index 1c35b51..e6d1c59 100644 --- a/kernel/port/esp32c6/CMakeLists.txt +++ b/kernel/port/esp32c6/CMakeLists.txt @@ -7,8 +7,8 @@ set(target_arch "rv32imac_zicsr_zifencei") set(target_abi "ilp32") set(port_src - ${CMAKE_CURRENT_LIST_DIR}/src/hal/gpio.c - ${CMAKE_CURRENT_LIST_DIR}/src/hal/i2c.c + # ${CMAKE_CURRENT_LIST_DIR}/src/hal/gpio.c + # ${CMAKE_CURRENT_LIST_DIR}/src/hal/i2c.c ${CMAKE_CURRENT_LIST_DIR}/src/hal/spi.c ${CMAKE_CURRENT_LIST_DIR}/src/clkconfig.c @@ -19,9 +19,6 @@ set(port_src ) set(port_include ${CMAKE_CURRENT_LIST_DIR}/include - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/include - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/esp-idf/components/soc/esp32c6/include - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/esp-idf/components/soc/include ) set(port_link -T${CMAKE_CURRENT_LIST_DIR}/linker.ld diff --git a/kernel/port/esp32c6/include/soc/io_mux_struct.h b/kernel/port/esp32c6/include/soc/io_mux_struct.h index ac328c4..530997e 100644 --- a/kernel/port/esp32c6/include/soc/io_mux_struct.h +++ b/kernel/port/esp32c6/include/soc/io_mux_struct.h @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT +#pragma once + #include // I2S output clock selection. @@ -33,8 +35,8 @@ typedef union { } io_mux_gpio_t; typedef struct io_mux_t { - volatile io_mux_clk_t clk; - volatile io_mux_gpio_t gpio[31]; + io_mux_clk_t volatile clk; + io_mux_gpio_t volatile gpio[31]; } io_mux_t; extern io_mux_t IO_MUX; diff --git a/kernel/port/esp32c6/linker.ld b/kernel/port/esp32c6/linker.ld index 79f7f04..164bad2 100644 --- a/kernel/port/esp32c6/linker.ld +++ b/kernel/port/esp32c6/linker.ld @@ -25,6 +25,8 @@ SECTIONS /* Import hardware addresses. */ INCLUDE esp32c6.peripherals.ld +INCLUDE esp32c6.rom.ld +INCLUDE esp32c6.rom.api.ld PROVIDE(INTPRI = 0x600C5000); PROVIDE(PLIC_MX = 0x20001000); PROVIDE(PLIC_UX = 0x20001400); diff --git a/kernel/port/esp32c6/src/hal/i2c.c b/kernel/port/esp32c6/src/hal/i2c.c index b90d3d6..0a0efed 100644 --- a/kernel/port/esp32c6/src/hal/i2c.c +++ b/kernel/port/esp32c6/src/hal/i2c.c @@ -5,6 +5,7 @@ #include "hal/gpio.h" #include "port/clkconfig.h" +#include "scheduler/scheduler.h" #include "soc/gpio_sig_map.h" #include "soc/gpio_struct.h" #include "soc/i2c_struct.h" @@ -39,6 +40,12 @@ typedef union { +// Returns the amount of I²C peripherals present. +// Cannot produce an error. +int i2c_count() { + return 1; +} + // Load commands into the command buffer. static void i2c_master_load_comd(i2c_comd_val_t *comd, size_t count) { assert_dev_drop(count > 0 && count <= 8); @@ -95,10 +102,12 @@ void i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int } // Clock configuration. + clkconfig_i2c0(bitrate * 10, true, true); clkconfig_i2c0(bitrate * 10, true, false); // I2C master configuration. I2C0.ctr = (i2c_ctr_reg_t){ + .fsm_rst = true, .sda_force_out = true, .scl_force_out = true, .ms_mode = true, @@ -124,8 +133,8 @@ void i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int .time_out_value = 16, .time_out_en = true, }; - I2C0.scl_st_time_out.val = 0x10; - I2C0.scl_main_st_time_out.val = 0x10; + I2C0.scl_st_time_out.val = 23; + I2C0.scl_main_st_time_out.val = 23; I2C0.sda_hold.sda_hold_time = 30; I2C0.sda_sample.sda_sample_time = 30; @@ -141,10 +150,12 @@ void i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int I2C0.ctr.conf_upgate = true; // Make GPIO open-drain. - GPIO.pin[sda_pin] = (gpio_pin_reg_t){.pad_driver = true}; - GPIO.pin[scl_pin] = (gpio_pin_reg_t){.pad_driver = true}; + timestamp_us_t time = time_us(); + while (time_us() < time + 10000) sched_yield(); IO_MUX.gpio[sda_pin] = (io_mux_gpio_t){.mcu_sel = 1, .fun_ie = true, .mcu_ie = true}; IO_MUX.gpio[scl_pin] = (io_mux_gpio_t){.mcu_sel = 1, .fun_ie = true, .mcu_ie = true}; + GPIO.pin[sda_pin] = (gpio_pin_reg_t){.pad_driver = true}; + GPIO.pin[scl_pin] = (gpio_pin_reg_t){.pad_driver = true}; // GPIO matrix configuration. GPIO.func_out_sel_cfg[sda_pin] = (gpio_func_out_sel_cfg_reg_t){ @@ -201,7 +212,7 @@ size_t i2c_master_read_from(badge_err_t *ec, int i2c_num, int slave_id, void *ra // Address. { .op_code = I2C_OPC_WRITE, - .ack_check_en = true, + .ack_check_en = 0, // true, .ack_exp = I2C_ACK, .ack_value = I2C_ACK, .byte_num = 1 + addr_10bit, @@ -230,8 +241,7 @@ size_t i2c_master_read_from(badge_err_t *ec, int i2c_num, int slave_id, void *ra // Wait for transaction to finish. timestamp_us_t to = time_us() + 10000; - while (I2C0.sr.bus_busy && time_us() < to) - ; + while (I2C0.sr.bus_busy && time_us() < to); for (size_t i = 0; i < len; i++) { buf[i] = I2C0.data.fifo_rdata; @@ -252,6 +262,8 @@ size_t i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void cons } // Put address in the FIFO. + logkf(LOG_DEBUG, "I2C main state: %{u32;d}", I2C0.sr.scl_main_state_last); + logkf(LOG_DEBUG, "I2C SCL state: %{u32;d}", I2C0.sr.scl_state_last); i2c_clear_fifo(true, true); bool addr_10bit = i2c_master_queue_addr(slave_id, false); @@ -264,7 +276,7 @@ size_t i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void cons // Address. { .op_code = I2C_OPC_WRITE, - .ack_check_en = true, + .ack_check_en = 0, // true, .ack_exp = I2C_ACK, .ack_value = I2C_ACK, .byte_num = 1 + addr_10bit, @@ -304,8 +316,7 @@ size_t i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void cons I2C0.ctr.trans_start = true; // Wait for transaction to finish. - while (I2C0.sr.bus_busy) - ; + while (I2C0.sr.bus_busy); return 0; } diff --git a/kernel/port/esp32c6/src/hal/spi.c b/kernel/port/esp32c6/src/hal/spi.c index a7843c8..8098d8f 100644 --- a/kernel/port/esp32c6/src/hal/spi.c +++ b/kernel/port/esp32c6/src/hal/spi.c @@ -3,32 +3,32 @@ #include "hal/spi.h" -#include - -#include "interrupt.h" #include "hal/gpio.h" +#include "interrupt.h" #include "port/clkconfig.h" #include "port/hardware_allocation.h" #include "soc/gpio_sig_map.h" #include "soc/gpio_struct.h" -#include "soc/spi_struct.h" #include "soc/io_mux_struct.h" +#include "soc/spi_struct.h" + +#include static void spi_clear_fifo(bool clear_rxfifo, bool clear_txfifo) { GPSPI2.dma_conf = (spi_dma_conf_reg_t){ .buf_afifo_rst = clear_txfifo, - .rx_afifo_rst = clear_rxfifo, + .rx_afifo_rst = clear_rxfifo, }; GPSPI2.dma_conf = (spi_dma_conf_reg_t){ .buf_afifo_rst = false, - .rx_afifo_rst = false, + .rx_afifo_rst = false, }; } static void spi_config_apply(void) { // Apply the register configurations and wait until it's done. GPSPI2.cmd.update = 1; - while(GPSPI2.cmd.update); + while (GPSPI2.cmd.update); } static void spi_isr(void) { @@ -55,14 +55,20 @@ static void spi_int_config(bool enable, int channel) { irq_enable(mie); } -void spi_controller_init(badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate) { + + +// Returns the amount of SPI peripherals present. +// Cannot produce an error. +int spi_count() { + return 1; +} + +void spi_controller_init( + badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate +) { // Bounds check. - if (spi_num != 0 - || sclk_pin < 0 || sclk_pin >= io_count() - || mosi_pin < 0 || mosi_pin >= io_count() - || miso_pin < 0 || miso_pin >= io_count() - || ss_pin < 0 || ss_pin >= io_count() - ) { + if (spi_num != 0 || sclk_pin < 0 || sclk_pin >= io_count() || mosi_pin < 0 || mosi_pin >= io_count() || + miso_pin < 0 || miso_pin >= io_count() || ss_pin < 0 || ss_pin >= io_count()) { badge_err_set(ec, ELOC_SPI, ECAUSE_RANGE); return; } @@ -90,10 +96,12 @@ void spi_controller_init(badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pi spi_config_apply(); // Set pins to GPIO function and enable input for MISO - IO_MUX.gpio[sclk_pin] = (io_mux_gpio_t){.mcu_sel = 1,}; + IO_MUX.gpio[sclk_pin] = (io_mux_gpio_t){ + .mcu_sel = 1, + }; IO_MUX.gpio[miso_pin] = (io_mux_gpio_t){.mcu_sel = 1, .fun_ie = true}; IO_MUX.gpio[mosi_pin] = (io_mux_gpio_t){.mcu_sel = 1}; - IO_MUX.gpio[ss_pin] = (io_mux_gpio_t){.mcu_sel = 1}; + IO_MUX.gpio[ss_pin] = (io_mux_gpio_t){.mcu_sel = 1}; // GPIO matrix configuration. GPIO.func_out_sel_cfg[sclk_pin] = (gpio_func_out_sel_cfg_reg_t){ @@ -123,8 +131,8 @@ void spi_controller_init(badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pi } static void spi_controller_transfer_generic(badge_err_t *ec, int spi_num, void *buf, size_t len) { - const int data_buf_len = sizeof(GPSPI2.data_buf); - uint32_t words [data_buf_len/sizeof(GPSPI2.data_buf[0])]; + int const data_buf_len = sizeof(GPSPI2.data_buf); + uint32_t words[data_buf_len / sizeof(GPSPI2.data_buf[0])]; // Bounds check. if (spi_num != 0) { @@ -141,7 +149,7 @@ static void spi_controller_transfer_generic(badge_err_t *ec, int spi_num, void * mem_copy(words, buf, copy_len); mem_copy((void *)GPSPI2.data_buf, words, data_buf_len); // TODO: optimize copy length } - + // prepare for transfer GPSPI2.ms_dlen.ms_data_bitlen = copy_len * 8 - 1; spi_clear_fifo(true, true); @@ -149,7 +157,7 @@ static void spi_controller_transfer_generic(badge_err_t *ec, int spi_num, void * // Start transfer and wait for completion GPSPI2.cmd.usr = 1; - while(GPSPI2.cmd.usr); // TODO: yield? + while (GPSPI2.cmd.usr); // TODO: yield? if (GPSPI2.user.usr_miso) { // copy back received data @@ -172,13 +180,13 @@ void spi_controller_write(badge_err_t *ec, int spi_num, void const *buf, size_t GPSPI2.user.usr_mosi = 1; GPSPI2.user.usr_miso = 0; - spi_controller_transfer_generic(ec, spi_num, (void*) buf, len); + spi_controller_transfer_generic(ec, spi_num, (void *)buf, len); } void spi_controller_transfer(badge_err_t *ec, int spi_num, void *buf, size_t len, bool fdx) { GPSPI2.user.usr_mosi = 1; GPSPI2.user.usr_miso = 1; - GPSPI2.user.doutdin = fdx; + GPSPI2.user.doutdin = fdx; spi_controller_transfer_generic(ec, spi_num, buf, len); } diff --git a/kernel/port/esp32c6/src/interrupt.c b/kernel/port/esp32c6/src/interrupt.c index d527571..9b7f849 100644 --- a/kernel/port/esp32c6/src/interrupt.c +++ b/kernel/port/esp32c6/src/interrupt.c @@ -94,11 +94,31 @@ void irq_ch_set_isr(int int_irq, isr_t isr) { // Callback from ASM to platform-specific interrupt handler. void riscv_interrupt_handler() { + static timestamp_us_t last_time = 0; + static unsigned long count = 0; + // Get interrupt cause. - int mcause; + long mcause; asm("csrr %0, mcause" : "=r"(mcause)); mcause &= 31; + timestamp_us_t now = time_us(); + if (now > last_time + 1000) { + last_time = now; + count = 0; + } else if (count < 100) { + count++; + } else { + logk_from_isr(LOG_FATAL, "Interrupt storm detected"); + logkf_from_isr(LOG_FATAL, "MCAUSE: %{long;x}", mcause); + for (int i = 0; i < EXT_IRQ_COUNT; i++) { + if (irq_ch_ext_pending(i)) { + logkf_from_isr(LOG_FATAL, "Pending: %{d}", i); + } + } + panic_abort(); + } + // Jump to ISR. if (isr_table[mcause]) { isr_table[mcause](); @@ -130,3 +150,15 @@ bool irq_ch_enabled(int int_irq) { asm("csrr %0, mie" : "=r"(mask)); return ((mask) >> int_irq) & 1; } + +// Query whether an internal interrupt is pending. +bool irq_ch_pending(int int_irq) { + long mask; + asm("csrr %0, mip" : "=r"(mask)); + return ((mask) >> int_irq) & 1; +} + +// Query whether an external interrupt is pending. +bool irq_ch_ext_pending(int ext_irq) { + return (INTMTX.status[ext_irq >> 5] >> (ext_irq & 31)) & 1; +} diff --git a/kernel/port/esp32c6/src/port.c b/kernel/port/esp32c6/src/port.c index 11d088e..46f36f8 100644 --- a/kernel/port/esp32c6/src/port.c +++ b/kernel/port/esp32c6/src/port.c @@ -3,8 +3,11 @@ #include "port/port.h" +#include "interrupt.h" #include "port/clkconfig.h" +#include "port/hardware_allocation.h" #include "port/pmu_init.h" +#include "soc/ext_irq.h" #include "soc/pcr_struct.h" #include "soc/uart_struct.h" #include "soc/usb_serial_jtag_struct.h" @@ -26,6 +29,10 @@ void port_early_init() { // Full hardware initialization. void port_init() { + extern void esp_i2c_isr(); + irq_ch_route(EXT_IRQ_I2C_EXT0_INTR, INT_CHANNEL_I2C); + irq_ch_set_isr(INT_CHANNEL_I2C, esp_i2c_isr); + irq_ch_enable(INT_CHANNEL_I2C, true); } // Send a single character to the log output. diff --git a/kernel/port/esp32p4/CMakeLists.txt b/kernel/port/esp32p4/CMakeLists.txt index 3a99903..9e32f60 100644 --- a/kernel/port/esp32p4/CMakeLists.txt +++ b/kernel/port/esp32p4/CMakeLists.txt @@ -17,11 +17,7 @@ set(port_src ${CMAKE_CURRENT_LIST_DIR}/src/port.c ) set(port_include - ${CMAKE_CURRENT_LIST_DIR}/include/ - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/include/ - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/esp-idf/components/soc/esp32p4/include/ - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/esp-idf/components/soc/include/ - ${CMAKE_CURRENT_LIST_DIR}/../esp_common/esp-idf/components/esp_rom/include/esp32p4/ + ${CMAKE_CURRENT_LIST_DIR}/include ) set(port_link -T${CMAKE_CURRENT_LIST_DIR}/linker.ld diff --git a/kernel/port/esp32p4/linker.ld b/kernel/port/esp32p4/linker.ld index 42b3f4a..e0fa3c7 100644 --- a/kernel/port/esp32p4/linker.ld +++ b/kernel/port/esp32p4/linker.ld @@ -27,6 +27,7 @@ SECTIONS /* Import hardware addresses. */ INCLUDE esp32p4.peripherals.ld INCLUDE esp32p4.rom.ld +INCLUDE esp32p4.rom.api.ld PROVIDE(CACHE = 0x3FF10000); PROVIDE(INTMTX0 = 0x500D6000); PROVIDE(INTMTX1 = 0x500D6800); diff --git a/kernel/port/esp32p4/src/port.c b/kernel/port/esp32p4/src/port.c index 92d5144..f0bcf2d 100644 --- a/kernel/port/esp32p4/src/port.c +++ b/kernel/port/esp32p4/src/port.c @@ -19,6 +19,10 @@ void port_early_init() { // Full hardware initialization. void port_init() { + extern void esp_i2c_isr(); + irq_ch_route(EXT_IRQ_I2C_EXT0_INTR, INT_CHANNEL_I2C); + irq_ch_set_isr(INT_CHANNEL_I2C, esp_i2c_isr); + irq_ch_enable(INT_CHANNEL_I2C, true); } // Send a single character to the log output. diff --git a/kernel/port/esp_common/CMakeLists.txt b/kernel/port/esp_common/CMakeLists.txt index cf4292a..810a490 100644 --- a/kernel/port/esp_common/CMakeLists.txt +++ b/kernel/port/esp_common/CMakeLists.txt @@ -4,5 +4,20 @@ cmake_minimum_required(VERSION 3.10.0) set(port_src ${port_src} + ${CMAKE_CURRENT_LIST_DIR}/src/gpio.c + ${CMAKE_CURRENT_LIST_DIR}/src/i2c.c ${CMAKE_CURRENT_LIST_DIR}/src/time.c -) \ No newline at end of file +) +set(port_include ${port_include} + ${CMAKE_CURRENT_LIST_DIR}/include/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/soc/${BADGEROS_PORT}/include/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/soc/include/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/hal/${BADGEROS_PORT}/include/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/hal/include/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/esp_rom/include/${BADGEROS_PORT}/ + ${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/esp_rom/include/ +) +set(port_link ${port_link} + -L${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/soc/${BADGEROS_PORT}/ld/ + -L${CMAKE_CURRENT_LIST_DIR}/esp-idf/components/esp_rom/${BADGEROS_PORT}/ld/ +) diff --git a/kernel/port/esp_common/include/esp_assert.h b/kernel/port/esp_common/include/esp_assert.h index 5b7ff6c..392ce77 100644 --- a/kernel/port/esp_common/include/esp_assert.h +++ b/kernel/port/esp_common/include/esp_assert.h @@ -7,3 +7,5 @@ #include "assertions.h" #define assert assert_dev_drop + +#define ESP_STATIC_ASSERT(...) _Static_assert(__VA_ARGS__) diff --git a/kernel/port/esp_common/include/hal/assert.h b/kernel/port/esp_common/include/hal/assert.h new file mode 100644 index 0000000..e1648ce --- /dev/null +++ b/kernel/port/esp_common/include/hal/assert.h @@ -0,0 +1,11 @@ + +// SPDX-License-Identifier: MIT +// Port of hal/assert.h + +#pragma once + +#include "assertions.h" +#include "cpu/panic.h" + +#define HAL_ASSERT(__e) assert_dev_drop(__e) +extern void abort(); diff --git a/kernel/port/esp_common/include/hal/log.h b/kernel/port/esp_common/include/hal/log.h new file mode 100644 index 0000000..abec4cd --- /dev/null +++ b/kernel/port/esp_common/include/hal/log.h @@ -0,0 +1,5 @@ + +// SPDX-License-Identifier: MIT +// Port of hal/log.h + +#pragma once diff --git a/kernel/port/esp_common/include/hal/misc.h b/kernel/port/esp_common/include/hal/misc.h new file mode 100644 index 0000000..b2a6571 --- /dev/null +++ b/kernel/port/esp_common/include/hal/misc.h @@ -0,0 +1,80 @@ + +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#define HAL_SWAP16(d) __builtin_bswap16((d)) +#define HAL_SWAP32(d) __builtin_bswap32((d)) +#define HAL_SWAP64(d) __builtin_bswap64((d)) + +/** + * @brief Macro to force a 32-bit read, modify, then write on a peripheral register + * + * Due to a GCC bug, the compiler may still try to optimize read/writes to peripheral register fields by using 8/16 bit + * access, even if they are marked volatile (i.e., -fstrict-volatile-bitfields has no effect). + * + * For ESP chips, the peripheral bus only allows 32-bit read/writes. The following macro works around the compiler issue + * by forcing a 32-bit read/modify/write. + * + * @note This macro should only be called on register fields of xxx_struct.h type headers, as it depends on the presence + * of a 'val' field of the register union. + * @note Current implementation reads into a uint32_t instead of copy base_reg direclty to temp_reg. The reason being + * that C++ does not create a copy constructor for volatile structs. + */ +#define HAL_FORCE_MODIFY_U32_REG_FIELD(base_reg, reg_field, field_val) \ + { \ + uint32_t temp_val = base_reg.val; \ + typeof(base_reg) temp_reg; \ + temp_reg.val = temp_val; \ + temp_reg.reg_field = (field_val); \ + (base_reg).val = temp_reg.val; \ + } + +/** + * @brief Macro to force a 32-bit read on a peripheral register + * + * @note This macro should only be called on register fields of xxx_struct.h type headers. See description above for + * more details. + * @note Current implementation reads into a uint32_t. See description above for more details. + */ +#define HAL_FORCE_READ_U32_REG_FIELD(base_reg, reg_field) \ + ({ \ + uint32_t temp_val = base_reg.val; \ + typeof(base_reg) temp_reg; \ + temp_reg.val = temp_val; \ + temp_reg.reg_field; \ + }) + +/** + * @brief Copy data from memory array to another memory + * + * This helps bypass the -Warray-bounds, -Wstringop-overread and -Wstringop-overflow bugs. + * + * @param dst_mem Pointer to the destination of data + * @param src_mem Pointer to the source of data to be copied + * @param len The number of bytes to be copied + * @return a pointer to destination + */ +#define hal_memcpy(dst_mem, src_mem, len) \ + (__extension__({ \ + mem_copy(dst_mem, src_mem, len); \ + dst_mem; \ + })) + +/** + * @brief Sets the first num bytes of the block of memory pointed by ptr to the specified value + * + * This helps bypass the -Warray-bounds, -Wstringop-overread and -Wstringop-overflow bugs. + * + * @param dst_reg Pointer to the block of memory to fill + * @param value The value to be set. + * @param len The number of bytes to be copied + * @return a pointer to the memory area + */ +#define hal_memset(dst_mem, value, len) \ + (__extension__({ \ + mem_set(dst_mem, src_mem, len); \ + dst_mem; \ + })) diff --git a/kernel/port/esp_common/include/hal/regi2c_ctrl.h b/kernel/port/esp_common/include/hal/regi2c_ctrl.h new file mode 100644 index 0000000..2df56ce --- /dev/null +++ b/kernel/port/esp_common/include/hal/regi2c_ctrl.h @@ -0,0 +1,20 @@ + +// SPDX-License-Identifier: MIT +// Port of hal/regi2c_ctrl.h + +#pragma once + +#define REGI2C_WRITE(x, y, z) \ + do { \ + __builtin_trap(); \ + (void)(x); \ + (void)(y); \ + (void)(z); \ + } while (0) +#define REGI2C_WRITE_MASK(x, y, z) \ + do { \ + __builtin_trap(); \ + (void)(x); \ + (void)(y); \ + (void)(z); \ + } while (0) diff --git a/kernel/port/esp32c6/src/hal/gpio.c b/kernel/port/esp_common/src/gpio.c similarity index 50% rename from kernel/port/esp32c6/src/hal/gpio.c rename to kernel/port/esp_common/src/gpio.c index a75e15f..ceb4d84 100644 --- a/kernel/port/esp32c6/src/hal/gpio.c +++ b/kernel/port/esp_common/src/gpio.c @@ -3,17 +3,34 @@ #include "hal/gpio.h" -#include "soc/gpio_ext_struct.h" -#include "soc/gpio_struct.h" +#ifdef BADGEROS_PORT_esp32c6 #include "soc/io_mux_struct.h" +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +// NOLINTBEGIN +#define STDLIB_H +#define _STDLIB_H +#define __STDLIB_H +// NOLINTEND +#include "hal/gpio_ll.h" +#include "soc/gpio_sig_map.h" +#pragma GCC diagnostic pop // Unsafe check if a pin has a function assigned. static inline bool io_has_function(int pin) { - return GPIO.func_out_sel_cfg[pin].out_sel != 128; + return GPIO.func_out_sel_cfg[pin].out_sel != SIG_GPIO_OUT_IDX; } +// Returns the amount of GPIO pins present. +// Cannot produce an error. +int io_count() { + return SOC_GPIO_PIN_COUNT; +} + // Sets the mode of GPIO pin `pin` to `mode`. void io_mode(badge_err_t *ec, int pin, io_mode_t mode) { if (pin < 0 || pin >= io_count()) { @@ -28,17 +45,35 @@ void io_mode(badge_err_t *ec, int pin, io_mode_t mode) { switch (mode) { default: badge_err_set(ec, ELOC_GPIO, ECAUSE_PARAM); break; case IO_MODE_HIGH_Z: { - GPIO.enable.val &= ~(1 << pin); + gpio_ll_output_disable(&GPIO, pin); } break; case IO_MODE_OUTPUT: { - GPIO.enable.val |= 1 << pin; + gpio_ll_output_enable(&GPIO, pin); } break; case IO_MODE_INPUT: { - GPIO.enable.val &= ~(1 << pin); + gpio_ll_output_disable(&GPIO, pin); } break; } } +// Get the mode of GPIO pin `pin`. +io_mode_t io_getmode(badge_err_t *ec, int pin) { + if (pin < 0 || pin >= io_count()) { + badge_err_set(ec, ELOC_GPIO, ECAUSE_RANGE); + return IO_MODE_HIGH_Z; + } + badge_err_set_ok(ec); +#if SOC_GPIO_PIN_COUNT > 32 + if (pin > 32) { + pin -= 32; + return (GPIO.enable.val >> pin) & 1 ? IO_MODE_OUTPUT : IO_MODE_INPUT; + } else +#endif + { + return (GPIO.enable.val >> pin) & 1 ? IO_MODE_OUTPUT : IO_MODE_INPUT; + } +} + // Sets the pull resistor behaviour of GPIO pin `pin` to `dir`. void io_pull(badge_err_t *ec, int pin, io_pull_t dir) { if (pin < 0 || pin >= io_count()) { @@ -50,32 +85,48 @@ void io_pull(badge_err_t *ec, int pin, io_pull_t dir) { switch (dir) { default: badge_err_set(ec, ELOC_GPIO, ECAUSE_PARAM); break; case IO_PULL_NONE: { - io_mux_gpio_t tmp = IO_MUX.gpio[pin]; - tmp.mcu_wpu = 0; - tmp.mcu_wpd = 0; - tmp.fun_wpu = 0; - tmp.fun_wpd = 0; - IO_MUX.gpio[pin] = tmp; + gpio_ll_pulldown_dis(&GPIO, pin); + gpio_ll_sleep_pulldown_dis(&GPIO, pin); + gpio_ll_pullup_dis(&GPIO, pin); + gpio_ll_sleep_pullup_dis(&GPIO, pin); } break; case IO_PULL_UP: { - io_mux_gpio_t tmp = IO_MUX.gpio[pin]; - tmp.mcu_wpu = 1; - tmp.mcu_wpd = 0; - tmp.fun_wpu = 1; - tmp.fun_wpd = 0; - IO_MUX.gpio[pin] = tmp; + gpio_ll_pulldown_dis(&GPIO, pin); + gpio_ll_sleep_pulldown_dis(&GPIO, pin); + gpio_ll_pullup_en(&GPIO, pin); + gpio_ll_sleep_pullup_en(&GPIO, pin); } break; case IO_PULL_DOWN: { - io_mux_gpio_t tmp = IO_MUX.gpio[pin]; - tmp.mcu_wpu = 0; - tmp.mcu_wpd = 1; - tmp.fun_wpu = 0; - tmp.fun_wpd = 1; - IO_MUX.gpio[pin] = tmp; + gpio_ll_pulldown_en(&GPIO, pin); + gpio_ll_sleep_pulldown_en(&GPIO, pin); + gpio_ll_pullup_dis(&GPIO, pin); + gpio_ll_sleep_pullup_dis(&GPIO, pin); } break; } } +// Get the pull resistor behaviour of GPIO pin `pin`. +io_pull_t io_getpull(badge_err_t *ec, int pin) { + if (pin < 0 || pin >= io_count()) { + badge_err_set(ec, ELOC_GPIO, ECAUSE_RANGE); + return IO_PULL_NONE; + } + badge_err_set_ok(ec); +#ifdef BADGEROS_PORT_esp32c6 + io_mux_gpio_t tmp = IO_MUX.gpio[pin]; +#endif +#ifdef BADGEROS_PORT_esp32p4 + iomux_gpio_reg_t tmp = IOMUX.gpio[pin]; +#endif + if (tmp.mcu_wpu) { + return IO_PULL_UP; + } else if (tmp.mcu_wpd) { + return IO_PULL_DOWN; + } else { + return IO_PULL_NONE; + } +} + // Writes level to GPIO pin pin. void io_write(badge_err_t *ec, int pin, bool level) { if (pin < 0 || pin >= io_count()) { @@ -87,11 +138,7 @@ void io_write(badge_err_t *ec, int pin, bool level) { } badge_err_set_ok(ec); - if (level) { - GPIO.out.val |= 1 << pin; - } else { - GPIO.out.val &= ~(1 << pin); - } + gpio_ll_set_level(&GPIO, pin, level); } // Reads logic level value from GPIO pin `pin`. @@ -106,7 +153,7 @@ bool io_read(badge_err_t *ec, int pin) { } badge_err_set_ok(ec); - return (GPIO.in.val >> (pin & 31)) & 1; + return gpio_ll_get_level(&GPIO, pin); } // Determine whether GPIO `pin` is claimed by a peripheral. diff --git a/kernel/port/esp_common/src/i2c.c b/kernel/port/esp_common/src/i2c.c new file mode 100644 index 0000000..596a89f --- /dev/null +++ b/kernel/port/esp_common/src/i2c.c @@ -0,0 +1,437 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/i2c.h" + +#include "badge_err.h" +#include "hal/gpio.h" +#include "interrupt.h" +#include "scheduler/scheduler.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +// NOLINTBEGIN +#define STDLIB_H +#define _STDLIB_H +#define __STDLIB_H +// NOLINTEND +#include "esp_rom_gpio.h" +#include "hal/clk_tree_ll.h" +#include "hal/gpio_hal.h" +#include "hal/gpio_ll.h" +#include "hal/i2c_hal.h" +#include "hal/i2c_ll.h" +#include "soc/gpio_sig_map.h" +#pragma GCC diagnostic pop + +#define I2C_ACK 0 +#define I2C_NACK 1 + +#define I2C_DEV (i2c_dev[i2c_num]) +#define I2C_COUNT ((int)SOC_I2C_NUM) + + + +typedef struct { + uint32_t sda_in_sig; + uint32_t scl_in_sig; + uint32_t sda_out_sig; + uint32_t scl_out_sig; +} i2c_sigtab_t; + +typedef struct { + bool addr_10bit; + uint8_t addr_buf[2]; +} i2c_fsm_addr_t; + +typedef struct { + uint8_t opcode; + bool ack_check; + bool ack_exp; + bool ack_resp; + size_t len; + uint8_t *buf; +} i2c_fsm_cmd_t; + +typedef struct { + int sda_pin; + int scl_pin; + atomic_int busy; + bool is_master; + bool enabled; + i2c_fsm_cmd_t *cmd; + size_t cmd_len; + size_t cur_cmd; + size_t cur_len; + size_t txd_cmd; + size_t rxd_cmd; + size_t txd_len; + size_t rxd_len; + size_t trans_bytes; +} i2c_ctx_t; + + + +// Returns the amount of I²C peripherals present. +// Cannot produce an error. +int i2c_count() { + return I2C_COUNT; +} + +// I²C dev table. +static i2c_dev_t *const i2c_dev[] = { + &I2C0, +#if SOC_I2C_NUM > 1 + &I2C1, +#endif +}; + +// I²C sig table. +static i2c_sigtab_t const i2c_sigtab[] = { + { + I2CEXT0_SDA_IN_IDX, + I2CEXT0_SCL_IN_IDX, + I2CEXT0_SDA_OUT_IDX, + I2CEXT0_SCL_OUT_IDX, + }, +#if SOC_I2C_NUM > 1 + { + I2CEXT1_SDA_IN_IDX, + I2CEXT1_SCL_IN_IDX, + I2CEXT1_SDA_OUT_IDX, + I2CEXT1_SCL_OUT_IDX, + }, +#endif +}; + +// Current pins in use. +static i2c_ctx_t i2c_ctx[I2C_COUNT] = {0}; + +static i2c_fsm_addr_t i2c_fmt_addr(int slave_id, bool rw_bit) { + if (slave_id > 127) { + return (i2c_fsm_addr_t){true, {0xf0 | ((slave_id >> 7) & 6) | rw_bit, slave_id}}; + } else { + return (i2c_fsm_addr_t){false, {(slave_id << 1) | rw_bit}}; + } +} + + + +// Queue as much of as many commands as possible. +static void i2c_queue_cmds(int i2c_num) { + int i; + for (i = 0; i < SOC_I2C_CMD_REG_NUM && i2c_ctx[i2c_num].cur_cmd < i2c_ctx[i2c_num].cmd_len; i++) { + i2c_fsm_cmd_t fsm_cmd = i2c_ctx[i2c_num].cmd[i2c_ctx[i2c_num].cur_cmd]; + size_t fsm_cmd_len = fsm_cmd.len - i2c_ctx[i2c_num].cur_len; + uint8_t byte_num = fsm_cmd_len <= 255 ? fsm_cmd_len : 255; + + i2c_ll_hw_cmd_t hw_cmd = { + .byte_num = byte_num, + .ack_en = fsm_cmd.ack_check, + .ack_exp = fsm_cmd.ack_exp, + .ack_val = fsm_cmd.ack_resp, + .op_code = fsm_cmd.opcode, + .done = false, + }; + i2c_ll_master_write_cmd_reg(I2C_DEV, hw_cmd, i); + + if (fsm_cmd.opcode == I2C_LL_CMD_WRITE || fsm_cmd.opcode == I2C_LL_CMD_READ) { + if (fsm_cmd_len <= 255) { + i2c_ctx[i2c_num].cur_cmd++; + i2c_ctx[i2c_num].cur_len = 0; + } else { + i2c_ctx[i2c_num].cur_len += byte_num; + } + } else { + i2c_ctx[i2c_num].cur_cmd++; + } + } + if (i < SOC_I2C_CMD_REG_NUM) { + i2c_ll_hw_cmd_t hw_cmd = {0}; + hw_cmd.op_code = I2C_LL_CMD_END; + i2c_ll_master_write_cmd_reg(I2C_DEV, hw_cmd, i); + } +} + +// Transmission done ISR. +static void i2c_isr_trans_done(int i2c_num) { + // Check for any remaining commands. + if (i2c_ctx[i2c_num].cur_cmd >= i2c_ctx[i2c_num].cmd_len) { + i2c_ll_clear_intr_mask(I2C_DEV, I2C_LL_INTR_MST_COMPLETE); + atomic_store(&i2c_ctx[i2c_num].busy, false); + return; + } + // If there are, queue them up. + i2c_queue_cmds(i2c_num); + i2c_ll_update(I2C_DEV); + i2c_ll_master_trans_start(I2C_DEV); +} + +// TXFIFO empty ISR. +static void i2c_isr_txfifo(int i2c_num) { + for (size_t i = 0; i < SOC_I2C_CMD_REG_NUM && i2c_ctx[i2c_num].txd_cmd < i2c_ctx[i2c_num].cmd_len; i++) { + uint32_t avl; + i2c_ll_get_txfifo_len(I2C_DEV, &avl); + i2c_fsm_cmd_t fsm_cmd = i2c_ctx[i2c_num].cmd[i2c_ctx[i2c_num].txd_cmd]; + size_t fsm_cmd_len = fsm_cmd.len - i2c_ctx[i2c_num].txd_len; + uint8_t byte_num = fsm_cmd_len <= avl ? fsm_cmd_len : avl; + + if (fsm_cmd.opcode == I2C_LL_CMD_WRITE) { + i2c_ll_write_txfifo(I2C_DEV, fsm_cmd.buf + i2c_ctx[i2c_num].txd_len, byte_num); + if (fsm_cmd_len <= avl) { + i2c_ctx[i2c_num].txd_cmd++; + i2c_ctx[i2c_num].txd_len = 0; + } else { + i2c_ctx[i2c_num].txd_len += byte_num; + } + } else { + i2c_ctx[i2c_num].txd_cmd++; + } + } + if (i2c_ctx[i2c_num].txd_cmd >= i2c_ctx[i2c_num].cmd_len) { + i2c_ll_disable_intr_mask(I2C_DEV, I2C_INTR_MST_TXFIFO_WM); + } + i2c_ll_clear_intr_mask(I2C_DEV, I2C_INTR_MST_TXFIFO_WM); +} + +// RXFIFO full ISR. +static void i2c_isr_rxfifo(int i2c_num) { + for (size_t i = 0; i < SOC_I2C_CMD_REG_NUM && i2c_ctx[i2c_num].rxd_cmd < i2c_ctx[i2c_num].cmd_len; i++) { + uint32_t avl; + i2c_ll_get_rxfifo_cnt(I2C_DEV, &avl); + i2c_fsm_cmd_t fsm_cmd = i2c_ctx[i2c_num].cmd[i2c_ctx[i2c_num].rxd_cmd]; + size_t fsm_cmd_len = fsm_cmd.len - i2c_ctx[i2c_num].rxd_len; + uint8_t byte_num = fsm_cmd_len <= avl ? fsm_cmd_len : avl; + + if (fsm_cmd.opcode == I2C_LL_CMD_READ) { + i2c_ll_read_rxfifo(I2C_DEV, fsm_cmd.buf + i2c_ctx[i2c_num].rxd_len, byte_num); + if (fsm_cmd_len <= avl) { + i2c_ctx[i2c_num].rxd_cmd++; + i2c_ctx[i2c_num].rxd_len = 0; + } else { + i2c_ctx[i2c_num].rxd_len += byte_num; + } + } else { + i2c_ctx[i2c_num].rxd_cmd++; + } + } + if (i2c_ctx[i2c_num].rxd_cmd >= i2c_ctx[i2c_num].cmd_len) { + i2c_ll_disable_intr_mask(I2C_DEV, I2C_INTR_MST_RXFIFO_WM); + } + i2c_ll_clear_intr_mask(I2C_DEV, I2C_INTR_MST_RXFIFO_WM); +} + +// Interrupt handler for I²C driver. +void esp_i2c_isr() { + for (int i2c_num = 0; i2c_num < I2C_COUNT; i2c_num++) { + uint32_t st; + i2c_ll_get_intr_mask(I2C_DEV, &st); + if (st & I2C_INTR_MST_TXFIFO_WM) { + logk_from_isr(LOG_DEBUG, "I2C_INTR_MST_TXFIFO_WM"); + i2c_isr_txfifo(i2c_num); + } + if (st & I2C_INTR_MST_RXFIFO_WM) { + logk_from_isr(LOG_DEBUG, "I2C_INTR_MST_RXFIFO_WM"); + i2c_isr_rxfifo(i2c_num); + } + if (st & I2C_LL_INTR_NACK) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_NACK"); + } + if (st & I2C_LL_INTR_TIMEOUT) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_TIMEOUT"); + } + if (st & I2C_LL_INTR_MST_COMPLETE) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_MST_COMPLETE"); + i2c_isr_trans_done(i2c_num); + } + if (st & I2C_LL_INTR_ARBITRATION) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_ARBITRATION"); + } + if (st & I2C_LL_INTR_END_DETECT) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_END_DETECT"); + } + if (st & I2C_LL_INTR_ST_TO) { + logk_from_isr(LOG_DEBUG, "I2C_LL_INTR_ST_TO"); + } + } +} + + + +// Initialises I²C peripheral i2c_num in slave mode with SDA pin `sda_pin`, SCL pin `scl_pin` and clock speed/bitrate +// bitrate. When initialised as an I²C master, the modes of the SDA and SCL pins are changed automatically. This +// function may be used again to change the settings on an initialised I²C peripheral in master mode. +void i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int32_t bitrate) { + // Bounds check. + if (i2c_num < 0 || i2c_num >= i2c_count() || sda_pin < 0 || sda_pin >= io_count() || scl_pin < 0 || + scl_pin >= io_count()) { + badge_err_set(ec, ELOC_I2C, ECAUSE_RANGE); + return; + } + gpio_hal_context_t hal = {&GPIO}; + + i2c_ctx[i2c_num].sda_pin = sda_pin; + i2c_ctx[i2c_num].scl_pin = scl_pin; + i2c_ctx[i2c_num].is_master = true; + i2c_ctx[i2c_num].enabled = true; + + // Configure pins. + gpio_ll_set_level(&GPIO, sda_pin, true); + io_pull(NULL, sda_pin, IO_PULL_NONE); + gpio_ll_od_enable(&GPIO, sda_pin); + gpio_hal_func_sel(&hal, scl_pin, PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(sda_pin, i2c_sigtab[i2c_num].sda_out_sig, false, false); + esp_rom_gpio_connect_in_signal(sda_pin, i2c_sigtab[i2c_num].sda_in_sig, false); + + gpio_ll_set_level(&GPIO, scl_pin, true); + io_pull(NULL, scl_pin, IO_PULL_NONE); + gpio_ll_od_enable(&GPIO, scl_pin); + gpio_hal_func_sel(&hal, scl_pin, PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(scl_pin, i2c_sigtab[i2c_num].scl_out_sig, false, false); + esp_rom_gpio_connect_in_signal(scl_pin, i2c_sigtab[i2c_num].scl_in_sig, false); + + // Configure clock. + i2c_ll_enable_bus_clock(i2c_num, true); + i2c_ll_reset_register(i2c_num); + i2c_ll_set_source_clk(I2C_DEV, I2C_CLK_SRC_XTAL); + i2c_ll_enable_controller_clock(I2C_DEV, true); + + // Configure hardware. + i2c_ll_master_init(I2C_DEV); + i2c_ll_set_data_mode(I2C_DEV, I2C_DATA_MODE_MSB_FIRST, I2C_DATA_MODE_MSB_FIRST); + i2c_ll_set_txfifo_empty_thr(I2C_DEV, 3); + i2c_ll_set_rxfifo_full_thr(I2C_DEV, 13); + i2c_ll_txfifo_rst(I2C_DEV); + i2c_ll_rxfifo_rst(I2C_DEV); + i2c_ll_update(I2C_DEV); + + // Set timing. + i2c_hal_clk_config_t clk_cal = {0}; + i2c_ll_master_cal_bus_clk(XTAL_CLK_FREQ, bitrate, &clk_cal); + i2c_ll_master_set_bus_timing(I2C_DEV, &clk_cal); + i2c_ll_master_set_fractional_divider(I2C_DEV, 0, 0); + i2c_ll_update(I2C_DEV); + i2c_ll_disable_intr_mask(I2C_DEV, -1); + + badge_err_set_ok(ec); +} + +// De-initialises I²C peripheral i2c_num in master mode. +void i2c_master_deinit(badge_err_t *ec, int i2c_num) { + // Bounds check. + if (i2c_num < 0 || i2c_num >= i2c_count()) { + badge_err_set(ec, ELOC_I2C, ECAUSE_RANGE); + return; + } + if (!i2c_ctx[i2c_num].is_master || !i2c_ctx[i2c_num].enabled) { + badge_err_set(ec, ELOC_I2C, ECAUSE_STATE); + return; + } + i2c_ctx[i2c_num].enabled = false; + + // Disable interrupts. + i2c_ll_disable_intr_mask(I2C_DEV, I2C_INTR_MST_TXFIFO_WM | I2C_INTR_MST_RXFIFO_WM); + + // Disable hardware. + i2c_ll_enable_controller_clock(I2C_DEV, false); + i2c_ll_enable_bus_clock(i2c_num, false); + + // Reset pins. + esp_rom_gpio_connect_out_signal(i2c_ctx[i2c_num].scl_pin, SIG_GPIO_OUT_IDX, false, false); + gpio_ll_od_disable(&GPIO, i2c_ctx[i2c_num].scl_pin); + gpio_ll_set_level(&GPIO, i2c_ctx[i2c_num].scl_pin, false); + + esp_rom_gpio_connect_out_signal(i2c_ctx[i2c_num].sda_pin, SIG_GPIO_OUT_IDX, false, false); + gpio_ll_od_disable(&GPIO, i2c_ctx[i2c_num].sda_pin); + gpio_ll_set_level(&GPIO, i2c_ctx[i2c_num].sda_pin, false); + + badge_err_set_ok(ec); +} + +// Performs an I²C transaction synchronously. +static size_t i2c_sync_trans(badge_err_t *ec, int i2c_num, i2c_fsm_cmd_t *cmd, size_t cmd_len) { + i2c_ll_txfifo_rst(I2C_DEV); + i2c_ll_rxfifo_rst(I2C_DEV); + + // Reset I²C state machine. + atomic_store(&i2c_ctx[i2c_num].busy, true); + i2c_ctx[i2c_num].trans_bytes = 0; + i2c_ctx[i2c_num].cur_cmd = 0; + i2c_ctx[i2c_num].cur_len = 0; + i2c_ctx[i2c_num].txd_len = 0; + i2c_ctx[i2c_num].txd_cmd = 0; + i2c_ctx[i2c_num].rxd_len = 0; + i2c_ctx[i2c_num].rxd_cmd = 0; + i2c_ctx[i2c_num].cmd = cmd; + i2c_ctx[i2c_num].cmd_len = cmd_len; + + // Reset I²C FSM. + i2c_ll_txfifo_rst(I2C_DEV); + i2c_ll_rxfifo_rst(I2C_DEV); + i2c_ll_master_fsm_rst(I2C_DEV); + // i2c_ll_master_clr_bus(I2C_DEV, I2C_LL_RESET_SLV_SCL_PULSE_NUM_DEFAULT); + + // Start transaction. + i2c_queue_cmds(i2c_num); + i2c_isr_txfifo(i2c_num); + i2c_ll_clear_intr_mask(I2C_DEV, -1); + i2c_ll_enable_intr_mask(I2C_DEV, I2C_LL_MASTER_EVENT_INTR | I2C_INTR_MST_TXFIFO_WM | I2C_INTR_MST_RXFIFO_WM); + i2c_ll_update(I2C_DEV); + logkf(LOG_DEBUG, "SR: %{u32;x}", I2C0.sr.val); + i2c_ll_master_trans_start(I2C_DEV); + uint32_t sr = I2C0.sr.val; + asm(""); + logkf(LOG_DEBUG, "SR: %{u32;x}", sr); + timestamp_us_t timeout = time_us() + 100000; + while (atomic_load(&i2c_ctx[i2c_num].busy) && time_us() < timeout) { + if (time_us() > timeout) { + badge_err_set(ec, ELOC_I2C, ECAUSE_TIMEOUT); + return i2c_ctx[i2c_num].trans_bytes; + } + sched_yield(); + } + logkf(LOG_DEBUG, "SR: %{u32;x}", I2C0.sr.val); + + badge_err_set_ok(ec); + return i2c_ctx[i2c_num].trans_bytes; +} + +// Reads len bytes into buffer buf from I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged read bytes. +size_t i2c_master_read_from(badge_err_t *ec, int i2c_num, int slave_id, void *raw_ptr, size_t len) { + // Bounds check. + if (i2c_num < 0 || i2c_num >= i2c_count() || !i2c_is_valid_addr(slave_id)) { + badge_err_set(ec, ELOC_I2C, ECAUSE_RANGE); + return 0; + } + + i2c_fsm_addr_t addr = i2c_fmt_addr(slave_id, I2C_MASTER_WRITE); + i2c_fsm_cmd_t i2c_ops[] = { + {I2C_LL_CMD_RESTART, 0, 0, 0, 0, NULL}, + {I2C_LL_CMD_WRITE, true, I2C_ACK, false, 1 + addr.addr_10bit, addr.addr_buf}, + {I2C_LL_CMD_READ, false, false, I2C_ACK, len, raw_ptr}, + {I2C_LL_CMD_STOP, 0, 0, 0, 0, NULL}, + }; + + return i2c_sync_trans(ec, i2c_num, i2c_ops, 4); +} + +// Writes len bytes from buffer buf to I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged written bytes. +size_t i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void const *raw_ptr, size_t len) { + // Bounds check. + if (i2c_num < 0 || i2c_num >= i2c_count() || !i2c_is_valid_addr(slave_id)) { + badge_err_set(ec, ELOC_I2C, ECAUSE_RANGE); + return 0; + } + + i2c_fsm_addr_t addr = i2c_fmt_addr(slave_id, I2C_MASTER_WRITE); + i2c_fsm_cmd_t i2c_ops[] = { + {I2C_LL_CMD_RESTART, 0, 0, 0, 0, NULL}, + {I2C_LL_CMD_WRITE, true, I2C_ACK, false, 1 + addr.addr_10bit, addr.addr_buf}, + {I2C_LL_CMD_WRITE, true, I2C_ACK, false, len, (void *)raw_ptr}, + {I2C_LL_CMD_STOP, 0, 0, 0, 0, NULL}, + }; + + return i2c_sync_trans(ec, i2c_num, i2c_ops, 4); +} diff --git a/kernel/src/badgelib/int_routines.c b/kernel/src/badgelib/int_routines.c index 1c431a4..c898a6e 100644 --- a/kernel/src/badgelib/int_routines.c +++ b/kernel/src/badgelib/int_routines.c @@ -8,6 +8,7 @@ #pragma GCC optimize("O2") #include +#include typedef int si_t __attribute__((mode(SI))); @@ -159,4 +160,52 @@ FAKE_OPER(di_t, __muldi3, *) FAKE_OPER(ti_t, __multi3, *) #endif +// The `__clz*` count leading zero functions count how many zeroes are present, starting at the MSB. +// They first convert a number into a bitmask where only bit above the most significant set bit is set. +// This is then multiplied with a de Bruijn sequence to get a unique index in the most significant bits. +// This index is then used to read from a hash table that uniquely identifies how many leading zeroes exist. + +int __clzsi2(uint32_t a) __attribute__((weak)); +int __clzsi2(uint32_t a) { + static uint8_t const hash_table[32] = { + 0, 31, 9, 30, 3, 8, 13, 29, 2, 5, 7, 21, 12, 24, 28, 19, + 1, 10, 4, 14, 6, 22, 25, 20, 11, 15, 23, 26, 16, 27, 17, 18, + }; + for (uint32_t i = 1; i < 32; i *= 2) { + a |= a >> i; + } + a++; + return hash_table[(a * 0x076be629) >> 27]; +} +int __clzdi2(uint64_t a) __attribute__((weak)); +int __clzdi2(uint64_t a) { + static uint8_t const hash_table[64] = { + 0, 63, 62, 57, 61, 51, 56, 45, 60, 39, 50, 36, 55, 30, 44, 24, 59, 47, 38, 26, 49, 18, + 35, 16, 54, 33, 29, 10, 43, 14, 23, 7, 1, 58, 52, 46, 40, 37, 31, 25, 48, 27, 19, 17, + 34, 11, 15, 8, 2, 53, 41, 32, 28, 20, 12, 9, 3, 42, 21, 13, 4, 22, 5, 6, + }; + for (uint64_t i = 1; i < 64; i *= 2) { + a |= a >> i; + } + a++; + return hash_table[(a * 0x0218a392cd3d5dbf) >> 58]; +} +#ifdef do_ti_math +int __clzti2(__uint128_t a) { + static uint8_t const hash_table[128] = { + 0, 127, 126, 120, 125, 113, 119, 106, 124, 99, 112, 92, 118, 85, 105, 78, 123, 95, 98, 71, 111, 64, + 91, 57, 117, 68, 84, 50, 104, 43, 77, 36, 122, 108, 94, 80, 97, 59, 70, 38, 110, 61, 63, 29, + 90, 27, 56, 22, 116, 88, 67, 46, 83, 25, 49, 15, 103, 54, 42, 12, 76, 20, 35, 8, 1, 121, + 114, 107, 100, 93, 86, 79, 96, 72, 65, 58, 69, 51, 44, 37, 109, 81, 60, 39, 62, 30, 28, 23, + 89, 47, 26, 16, 55, 13, 21, 9, 2, 115, 101, 87, 73, 66, 52, 45, 82, 40, 31, 24, 48, 17, + 14, 10, 3, 102, 74, 53, 41, 32, 18, 11, 4, 75, 33, 19, 5, 34, 6, 7, + }; + for (__uint128_t i = 1; i < 128; i *= 2) { + a |= a >> i; + } + a++; + return hash_table[(a * 0x01061438916347932a5cd9d3ead7b77f) >> 121]; +} +#endif + // NOLINTEND diff --git a/kernel/src/hal/syscall_impl.c b/kernel/src/hal/syscall_impl.c new file mode 100644 index 0000000..af4f14e --- /dev/null +++ b/kernel/src/hal/syscall_impl.c @@ -0,0 +1,247 @@ + +// SPDX-License-Identifier: MIT + +#include "hal/gpio.h" +#include "hal/i2c.h" +#include "hal/spi.h" +#include "syscall_util.h" + + + +// Returns the amount of GPIO pins present. +// Cannot produce an error. +int syscall_io_count() { + return io_count(); +} + +// Sets the mode of GPIO pin `pin` to `mode`. +void syscall_io_mode(badge_err_t *ec, int pin, io_mode_t mode) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + io_mode(ec, pin, mode); +} +// Get the mode of GPIO pin `pin`. +io_mode_t syscall_io_getmode(badge_err_t *ec, int pin) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_getmode(ec, pin); +} +// Sets the pull resistor behaviour of GPIO pin `pin` to `dir`. +void syscall_io_pull(badge_err_t *ec, int pin, io_pull_t dir) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_pull(ec, pin, dir); +} +// Get the pull resistor behaviour of GPIO pin `pin`. +io_pull_t syscall_io_getpull(badge_err_t *ec, int pin) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_getpull(ec, pin); +} +// Writes level to GPIO pin pin. +void syscall_io_write(badge_err_t *ec, int pin, bool level) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_write(ec, pin, level); +} +// Reads logic level value from GPIO pin `pin`. +// Returns false on error. +bool syscall_io_read(badge_err_t *ec, int pin) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_read(ec, pin); +} +// Determine whether GPIO `pin` is claimed by a peripheral. +// Returns false on error. +bool syscall_io_is_peripheral(badge_err_t *ec, int pin) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + return io_is_peripheral(ec, pin); +} + + + +// Returns the amount of I²C peripherals present. +// Cannot produce an error. +int syscall_i2c_count() { + return i2c_count(); +} + +// Initialises I²C peripheral i2c_num in slave mode with SDA pin `sda_pin`, SCL pin `scl_pin` and clock speed/bitrate +// bitrate. When initialised as an I²C master, the modes of the SDA and SCL pins are changed automatically. This +// function may be used again to change the settings on an initialised I²C peripheral in master mode. +void syscall_i2c_master_init(badge_err_t *ec, int i2c_num, int sda_pin, int scl_pin, int32_t bitrate) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + i2c_master_init(ec, i2c_num, sda_pin, scl_pin, bitrate); + badge_err_log_warn(ec); +} +// De-initialises I²C peripheral i2c_num in master mode. +void syscall_i2c_master_deinit(badge_err_t *ec, int i2c_num) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + i2c_master_deinit(ec, i2c_num); + badge_err_log_warn(ec); +} +// Reads len bytes into buffer buf from I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged read bytes. +size_t syscall_i2c_master_read_from(badge_err_t *ec, int i2c_num, int slave_id, void *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + sysutil_memassert_rw(buf, len); + size_t rv = i2c_master_read_from(ec, i2c_num, slave_id, buf, len); + badge_err_log_warn(ec); + return rv; +} +// Writes len bytes from buffer buf to I²C slave with ID slave_id. +// This function blocks until the entire transaction is completed and returns the number of acknowledged written bytes. +size_t syscall_i2c_master_write_to(badge_err_t *ec, int i2c_num, int slave_id, void const *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + sysutil_memassert_r(buf, len); + size_t rv = i2c_master_write_to(ec, i2c_num, slave_id, buf, len); + badge_err_log_warn(ec); + return rv; +} + + + +#ifdef BADGEROS_PORT_esp32p4 +// Returns the amount of SPI peripherals present. +// Cannot produce an error. +int syscall_spi_count() { + return 0; +} + +// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin +// `miso_pin`, SS pin `ss_pin` and clock speed/bitrate bitrate. The modes of the SCLK, MOSI, MISO and SS pins are +// changed automatically. This function may be used again to change the settings on an initialised SPI peripheral in +// controller mode. +void syscall_spi_controller_init( + badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate +) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + (void)spi_num; + (void)sclk_pin; + (void)mosi_pin; + (void)miso_pin; + (void)ss_pin; + (void)bitrate; + badge_err_set(ec, ELOC_SPI, ECAUSE_UNSUPPORTED); +} +// De-initialises SPI peripheral. +void syscall_spi_deinit(badge_err_t *ec, int spi_num) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + // TODO: spi_deinit is unimplemented. + // spi_deinit(ec, spi_num); + (void)spi_num; + badge_err_set_ok(ec); +} +// Reads len bytes into buffer buf from SPI device. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_read(badge_err_t *ec, int spi_num, void *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + (void)spi_num; + (void)buf; + (void)len; + badge_err_set(ec, ELOC_SPI, ECAUSE_UNSUPPORTED); +} +// Writes len bytes from buffer buf to SPI device. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_write(badge_err_t *ec, int spi_num, void const *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + (void)spi_num; + (void)buf; + (void)len; + badge_err_set(ec, ELOC_SPI, ECAUSE_UNSUPPORTED); +} +// Writes len bytes from buffer buf to SPI device, then reads len bytes into buffer buf from SPI device. +// Write and read happen simultaneously if the full-duplex flag fdx is set. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_transfer(badge_err_t *ec, int spi_num, void *buf, size_t len, bool fdx) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + (void)spi_num; + (void)buf; + (void)len; + (void)fdx; + badge_err_set(ec, ELOC_SPI, ECAUSE_UNSUPPORTED); +} +#else +// Returns the amount of SPI peripherals present. +// Cannot produce an error. +int syscall_spi_count() { + return spi_count(); +} + +// Initialises SPI peripheral spi_num in controller mode with SCLK pin `sclk_pin`, MOSI pin `mosi_pin`, MISO pin +// `miso_pin`, SS pin `ss_pin` and clock speed/bitrate bitrate. The modes of the SCLK, MOSI, MISO and SS pins are +// changed automatically. This function may be used again to change the settings on an initialised SPI peripheral in +// controller mode. +void syscall_spi_controller_init( + badge_err_t *ec, int spi_num, int sclk_pin, int mosi_pin, int miso_pin, int ss_pin, int32_t bitrate +) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + spi_controller_init(ec, spi_num, sclk_pin, mosi_pin, miso_pin, ss_pin, bitrate); +} +// De-initialises SPI peripheral. +void syscall_spi_deinit(badge_err_t *ec, int spi_num) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + // TODO: spi_deinit is unimplemented. + // spi_deinit(ec, spi_num); + (void)spi_num; + badge_err_set_ok(ec); +} +// Reads len bytes into buffer buf from SPI device. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_read(badge_err_t *ec, int spi_num, void *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + sysutil_memassert_rw(buf, len); + spi_controller_read(ec, spi_num, buf, len); +} +// Writes len bytes from buffer buf to SPI device. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_write(badge_err_t *ec, int spi_num, void const *buf, size_t len) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + sysutil_memassert_r(buf, len); + spi_controller_write(ec, spi_num, buf, len); +} +// Writes len bytes from buffer buf to SPI device, then reads len bytes into buffer buf from SPI device. +// Write and read happen simultaneously if the full-duplex flag fdx is set. +// This function blocks until the entire transaction is completed. +void syscall_spi_controller_transfer(badge_err_t *ec, int spi_num, void *buf, size_t len, bool fdx) { + if (ec) { + sysutil_memassert_rw(ec, sizeof(badge_err_t)); + } + sysutil_memassert_rw(buf, len); + spi_controller_transfer(ec, spi_num, buf, len, fdx); +} +#endif diff --git a/kernel/src/loading/kbelfx.c b/kernel/src/process/kbelfx.c similarity index 95% rename from kernel/src/loading/kbelfx.c rename to kernel/src/process/kbelfx.c index 6a50b9f..d0d9984 100644 --- a/kernel/src/loading/kbelfx.c +++ b/kernel/src/process/kbelfx.c @@ -88,8 +88,9 @@ bool kbelfx_seg_alloc(kbelf_inst inst, size_t segs_len, kbelf_segment *segs) { size_t end = segs[i].vaddr_req + segs[i].size; if (end > max_addr) max_addr = end; - // logkf(LOG_DEBUG, "Segment %{size;d}: %{size;x} - %{size;x}", i, start, end); + logkf(LOG_DEBUG, "Segment %{size;d}: %{size;x} - %{size;x}", i, start, end); } + logkf(LOG_DEBUG, "Require %{size;d} bytes", max_addr - min_addr); size_t vaddr_real = proc_map_raw(NULL, proc, min_addr, max_addr - min_addr, min_align, MEMPROTECT_FLAG_RWX); if (!vaddr_real) @@ -100,7 +101,7 @@ bool kbelfx_seg_alloc(kbelf_inst inst, size_t segs_len, kbelf_segment *segs) { segs[i].paddr = segs[i].vaddr_real; segs[i].laddr = segs[i].vaddr_real; segs[i].alloc_cookie = NULL; - // logkf(LOG_DEBUG, "Segment %{size;x} mapped to %{size;x}", i, segs[i].vaddr_real); + logkf(LOG_DEBUG, "Segment %{size;x} mapped to %{size;x}", i, segs[i].vaddr_real); } segs[0].alloc_cookie = (void *)vaddr_real; diff --git a/kernel/src/process/process.c b/kernel/src/process/process.c index 91dd667..e973590 100644 --- a/kernel/src/process/process.c +++ b/kernel/src/process/process.c @@ -649,26 +649,52 @@ pid_t proc_create(badge_err_t *ec, pid_t parent, char const *binary, int argc, c } // Delete a process and release any resources it had. -void proc_delete(pid_t pid) { +static bool proc_delete_impl(pid_t pid, bool only_prestart) { mutex_acquire(NULL, &proc_mtx, TIMESTAMP_US_MAX); process_t dummy = {.pid = pid}; process_t *dummy_ptr = &dummy; array_binsearch_t res = array_binsearch(procs, sizeof(process_t *), procs_len, &dummy_ptr, proc_sort_pid_cmp); if (!res.found) { mutex_release(NULL, &proc_mtx); - return; + return false; } process_t *handle = procs[res.index]; + // Check for pre-start-ness. + if (only_prestart && !(atomic_load(&handle->flags) & PROC_PRESTART)) { + mutex_release(NULL, &proc_mtx); + return false; + } + // Stop the possibly running process and release all run-time resources. proc_delete_runtime_raw(handle); + // Remove from parent's child list. + process_t *parent = handle->parent; + if (parent) { + mutex_acquire(NULL, &parent->mtx, TIMESTAMP_US_MAX); + dlist_remove(&parent->children, &handle->node); + mutex_release(NULL, &parent->mtx); + } + // Release kernel memory allocated to process. memprotect_destroy(&handle->memmap.mpu_ctx); free(handle->argv); free(handle); array_lencap_remove(&procs, sizeof(process_t *), &procs_len, &procs_cap, NULL, res.index); mutex_release(NULL, &proc_mtx); + + return true; +} + +// Delete a process only if it hasn't been started yet. +bool proc_delete_prestart(pid_t pid) { + return proc_delete_impl(pid, true); +} + +// Delete a process and release any resources it had. +void proc_delete(pid_t pid) { + proc_delete_impl(pid, false); } // Get the process' flags. diff --git a/kernel/src/process/syscall_impl.c b/kernel/src/process/syscall_impl.c index 2c58ee6..8f81ef2 100644 --- a/kernel/src/process/syscall_impl.c +++ b/kernel/src/process/syscall_impl.c @@ -10,9 +10,11 @@ #include "process/internal.h" #include "process/sighandler.h" #include "process/types.h" +#include "rawprint.h" #include "scheduler/cpu.h" #include "signal.h" #include "sys/wait.h" +#include "syscall_util.h" #include "usercopy.h" @@ -66,16 +68,8 @@ size_t syscall_proc_getargs(size_t cap, void *memory) { // Check required size. size_t required = proc->argv_size; if (cap >= required) { - // Check memory ownership. - if ((proc_map_contains_raw(proc, (size_t)memory, required) & MEMPROTECT_FLAG_RW) != MEMPROTECT_FLAG_RW) { - // Process does not own memory; raise SIGSEGV. - mutex_release_shared(NULL, &proc->mtx); - proc_sigsegv_handler(); - } - - // Okay to copy to process. - // TODO: Copy-to-user function? - mem_copy(memory, proc->argv, required); + // Buffer fits; copy to user. + sigsegv_assert(copy_to_user_raw(proc, (size_t)memory, proc->argv, required)); } mutex_release_shared(NULL, &proc->mtx); @@ -90,20 +84,14 @@ int syscall_proc_pcreate(char const *binary, int argc, char const *const *argv) // Verify validity of pointers. if (strlen_from_user_raw(proc, (size_t)binary, PTRDIFF_MAX) < 0) { - logk(LOG_DEBUG, "binary bad"); proc_sigsegv_handler(); } - if (argc < 0) { - logk(LOG_DEBUG, "argc bad"); - proc_sigsys_handler(); - } + sigsys_assert(argc >= 0); if (!proc_map_contains_raw(proc, (size_t)argv, argc * sizeof(char const *))) { - logk(LOG_DEBUG, "argv bad"); proc_sigsegv_handler(); } for (int i = 0; i < argc; i++) { if (strlen_from_user_raw(proc, (size_t)argv[i], PTRDIFF_MAX) < 0) { - logkf(LOG_DEBUG, "argv[%{d}] bad", i); proc_sigsegv_handler(); } } @@ -112,11 +100,19 @@ int syscall_proc_pcreate(char const *binary, int argc, char const *const *argv) return proc_create(NULL, proc->pid, binary, argc, argv); } +// Destroy a "pre-start" child process. +// Usually used in case of errors. +bool syscall_proc_pdestroy(int child) { + if (!proc_is_parent(proc_current()->pid, child)) { + return false; + } + return proc_delete_prestart(child); +} + // Starts a "pre-start" child process, thereby converting it into a running child process. bool syscall_proc_pstart(int child) { // Start a process. if (!proc_is_parent(proc_current()->pid, child)) { - logkf(LOG_DEBUG, "Process %{d} is not the parent of %{d}", proc_current()->pid, child); return false; } badge_err_t ec; @@ -127,9 +123,7 @@ bool syscall_proc_pstart(int child) { // Set the signal handler for a specific signal number. void *syscall_proc_sighandler(int signum, void *newhandler) { - if (signum < 0 || signum >= SIG_COUNT) { - proc_sigsys_handler(); - } + sigsys_assert(signum >= 0 && signum < SIG_COUNT); process_t *const proc = proc_current(); mutex_acquire(NULL, &proc->mtx, TIMESTAMP_US_MAX); void *old = (void *)proc->sighandlers[signum]; @@ -140,12 +134,8 @@ void *syscall_proc_sighandler(int signum, void *newhandler) { // Return from a signal handler. void syscall_proc_sigret() { - if (!sched_is_sighandler()) { - proc_sigsys_handler(); - } - if (!sched_signal_exit()) { - proc_sigsegv_handler(); - } + sigsys_assert(sched_is_sighandler()); + sigsegv_assert(sched_signal_exit()); irq_enable(false); sched_lower_from_isr(); isr_context_switch(); @@ -153,13 +143,10 @@ void syscall_proc_sigret() { } // Get child process status update. -int syscall_proc_waitpid(int pid, int *wstatus, int options) { +NOASAN int syscall_proc_waitpid(int pid, int *wstatus, int options) { process_t *proc = proc_current(); // Check memory ownership. - if ((size_t)wstatus % sizeof(int) || - (wstatus && (!(proc_map_contains_raw(proc, (size_t)wstatus, sizeof(int)) & MEMPROTECT_FLAG_W)))) { - proc_sigsegv_handler(); - } + sysutil_memassert_rw(wstatus, sizeof(int)); while (!(options & WNOHANG)) { mutex_acquire_shared(NULL, &proc->mtx, TIMESTAMP_US_MAX); @@ -199,7 +186,7 @@ int syscall_proc_waitpid(int pid, int *wstatus, int options) { } mutex_release_shared(NULL, &proc->mtx); if (!eligible) { - // No children with matchind PIDs exist. + // No children with matching PIDs exist. return -ECHILD; } sched_yield(); @@ -208,3 +195,13 @@ int syscall_proc_waitpid(int pid, int *wstatus, int options) { // Nothing found in non-blocking wait. return 0; } + + + +// Temporary write system call. +void syscall_temp_write(char const *message, size_t length) { + sysutil_memassert_r(message, length); + mutex_acquire(NULL, &log_mtx, TIMESTAMP_US_MAX); + rawprint_substr(message, length); + mutex_release(NULL, &log_mtx); +} diff --git a/kernel/src/process/syscall_util.c b/kernel/src/process/syscall_util.c new file mode 100644 index 0000000..a3c7793 --- /dev/null +++ b/kernel/src/process/syscall_util.c @@ -0,0 +1,35 @@ + +// SPDX-License-Identifier: MIT + +#include "syscall_util.h" + +#include "process/internal.h" +#include "process/sighandler.h" +#include "process/types.h" + + +// Assert that a condition is true, or raise SIGSEGV and don't return. +void sigsys_assert(bool condition) { + if (!condition) { + proc_sigsys_handler(); + } +} + +// Assert that a condition is true, or raise SIGSEGV and don't return. +void sigsegv_assert(bool condition) { + if (!condition) { + proc_sigsegv_handler(); + } +} + +// Checks whether the process has permission for a range of memory. +bool sysutil_memperm(void const *ptr, size_t len, uint32_t flags) { + return (proc_map_contains_raw(proc_current(), (size_t)ptr, len) & flags) == flags; +} + +// If the process does not have access, raise SIGSEGV and don't return. +void sysutil_memassert(void const *ptr, size_t len, uint32_t flags) { + if (!sysutil_memperm(ptr, len, flags)) { + proc_sigsegv_handler(); + } +} diff --git a/kernel/src/scheduler.c b/kernel/src/scheduler/scheduler.c similarity index 100% rename from kernel/src/scheduler.c rename to kernel/src/scheduler/scheduler.c diff --git a/kernel/src/scheduler/syscall_impl.c b/kernel/src/scheduler/syscall_impl.c new file mode 100644 index 0000000..834e20b --- /dev/null +++ b/kernel/src/scheduler/syscall_impl.c @@ -0,0 +1,9 @@ + +// SPDX-License-Identifier: MIT + +#include "scheduler/scheduler.h" +#include "syscall.h" + +void syscall_thread_yield() { + sched_yield(); +} diff --git a/kernel/src/syscall.c b/kernel/src/syscall.c index 0f6433b..db2e370 100644 --- a/kernel/src/syscall.c +++ b/kernel/src/syscall.c @@ -3,60 +3,43 @@ #include "syscall.h" -#include "cpu/isr.h" -#include "cpu/isr_ctx.h" -#include "cpu/panic.h" -#include "log.h" -#include "process/internal.h" -#include "process/process.h" -#include "process/sighandler.h" -#include "rawprint.h" -#include "scheduler/cpu.h" -#include "scheduler/scheduler.h" - -// Temporary write system call. -void syscall_temp_write(char const *message, size_t length) { - process_t *const proc = proc_current(); - if (proc_map_contains_raw(proc, (size_t)message, length) & MEMPROTECT_FLAG_R) { - mutex_acquire(NULL, &log_mtx, TIMESTAMP_US_MAX); - rawprint_substr(message, length); - mutex_release(NULL, &log_mtx); - } -} - -// System call handler jump table thing. -SYSCALL_HANDLER_SIGNATURE { - SYSCALL_HANDLER_IGNORE_UNUSED; - - long long retval = 0; - switch (sysnum) { - case SYSCALL_TEMP_WRITE: syscall_temp_write((char const *)a0, a1); break; - case SYSCALL_THREAD_YIELD: sched_yield(); break; - case SYSCALL_PROC_EXIT: syscall_proc_exit(a0); break; - case SYSCALL_PROC_GETARGS: retval = syscall_proc_getargs(a0, (void *)a1); break; - case SYSCALL_PROC_PCREATE: retval = syscall_proc_pcreate((char const *)a0, a1, (char const **)a2); break; - case SYSCALL_PROC_PSTART: retval = syscall_proc_pstart(a0); break; - case SYSCALL_PROC_SIGHANDLER: retval = (size_t)syscall_proc_sighandler(a0, (void *)a1); break; - case SYSCALL_PROC_SIGRET: syscall_proc_sigret(); break; - case SYSCALL_PROC_WAITPID: retval = syscall_proc_waitpid(a0, (int *)a1, a2); break; - case SYSCALL_FS_OPEN: retval = syscall_fs_open((char const *)a0, a1, a2); break; - case SYSCALL_FS_CLOSE: retval = syscall_fs_close(a0); break; - case SYSCALL_FS_READ: retval = syscall_fs_read(a0, (void *)a1, a2); break; - case SYSCALL_FS_WRITE: retval = syscall_fs_write(a0, (void const *)a1, a2); break; - case SYSCALL_FS_GETDENTS: retval = syscall_fs_getdents(a0, (void *)a1, a2); break; - case SYSCALL_MEM_ALLOC: retval = (size_t)syscall_mem_alloc(a0, a1, a2, a3); break; - case SYSCALL_MEM_SIZE: retval = syscall_mem_size((void *)a0); break; - case SYSCALL_MEM_DEALLOC: syscall_mem_dealloc((void *)a0); break; - case SYSCALL_SYS_SHUTDOWN: syscall_sys_shutdown(a0); break; - default: - proc_sigsys_handler(); - isr_global_disable(); - sched_lower_from_isr(); - isr_context_switch(); - __builtin_unreachable(); +// Table of system calls. +static syscall_info_t systab[] = { +#define SYSCALL_CAST (void (*)())(void *) +#define SYSCALL_DEF(no, enum, name, returns, ...) \ + [no] = { \ + SYSCALL_CAST name, \ + sizeof(returns), \ + SYSCALL_FLAG_EXISTS, \ + }, +#define SYSCALL_DEF_V(no, enum, name, ...) \ + [no] = { \ + SYSCALL_CAST name, \ + 0, \ + SYSCALL_FLAG_EXISTS, \ + }, +#define SYSCALL_DEF_F(no, enum, name, returns, ...) \ + [no] = { \ + SYSCALL_CAST name, \ + sizeof(returns), \ + SYSCALL_FLAG_EXISTS | SYSCALL_FLAG_FAST, \ + }, +#define SYSCALL_DEF_FV(no, enum, name, ...) \ + [no] = { \ + SYSCALL_CAST name, \ + 0, \ + SYSCALL_FLAG_EXISTS | SYSCALL_FLAG_FAST, \ + }, +#include "syscall_defs.inc" +}; +static int const systab_len = sizeof(systab) / sizeof(syscall_info_t); + +syscall_info_t syscall_info(int no) { + if (no < 0 || no >= systab_len) { + return (syscall_info_t){NULL, 0, 0}; + } else { + return systab[no]; } - - syscall_return(retval); } diff --git a/test/e2fs.iso b/test/e2fs.iso deleted file mode 100644 index 5b1cf15697505f3b1f7e84750916d108550d88b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2097152 zcmeI*JBSrm7y#gNA92_9{eXytZdC9QStX)qA!wmRS`9V11s_$4n8Z>Wu@S;r zXr~~E#E?d@6)eO;Fa`_35D5Ww3q^AM=iYT4@n&7uSN5Loz<=k=nKO_7oB1!d+1Zpd z0tB)Zs6^)7DGkJ8uq&mZSQbMgtv7l_3=f{TbGtvKMq}GQmF7@uJ+{A`lBNu=tdHf@ zYD&B7DfK_xaJ+Zv)}hPG7hL;d?SuWrl=t6ejC#lwzdrbU*Q&1vjve{!ue;wI|FM!b zrK!Vvl=B$%AaAj;H{f2e9NxDcgNxtdI1^#&_K9$juJILth4)XMnjIsHBEE_k>>5hd z6vZ0t>`&8H4yB*JYp%5USa9;&g>8ln5gd3L2;?iE z{`0-}GAE$^Jp%;t6;S{A-g}u7Q2(9*0{IG*>px!wnG+yDfB=C!1sYwW=bh(YMa!B% z9s;9RzpVra5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5(r3V{=MZuh^4k9Gd_%Rbhb{`)+CZ;oyClwRasEL*c{ z&HsmvKAX*qrWT{u?G zJiq?4OZnwo&baSMdF|8muWXL6{y99)gwNOm=w_!(H${4q9Iz zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNC9 HIReiC4F`yg diff --git a/test/fatfs.iso b/test/fatfs.iso deleted file mode 100644 index c92ca71209deb84613674576090fe8a375c5a3c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2097152 zcmeIyAxlG16ae7s6a>YwB$&L|EDtnW4BDIqwFtr!-*jy5jlEX}hW!M8hZt>wSd9A% zT5K!ECG{19)uw!h1Lwlwz~Q@aCR;aGomP>w(lXTMW&`(e3o}^H-CG2oNAZ;BO1K|9|`cY)^my0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ U009C72oNAZfB*pk1pcGI7bQzX8UO$Q diff --git a/test/list.c b/test/list.c deleted file mode 100644 index f6119f2..0000000 --- a/test/list.c +++ /dev/null @@ -1,390 +0,0 @@ -#include "list.h" - -#include "assertions.h" -#include "unittest.h" - -static void expect_list_eql(dlist_t list, dlist_node_t const *const *nodes, size_t nodes_size) { - size_t node_count = nodes_size / sizeof(dlist_node_t *); - - for (size_t i = 0; i < node_count; i++) { - EXPECT_TRUE(dlist_contains(&list, nodes[i])); - } - - EXPECT_EQL(node_count, list.len); - switch (node_count) { - case 0: - EXPECT_EQL(NULL, list.head); - EXPECT_EQL(NULL, list.tail); - break; - - default: { - EXPECT_EQL(nodes[0], list.head); - EXPECT_EQL(nodes[node_count - 1], list.tail); - - dlist_node_t const *iter = list.head; - for (size_t i = 0; i < node_count; i++, iter = iter->next) { - bool first = (i == 0); - bool last = (i == (node_count - 1)); - - EXPECT(iter != NULL); - - EXPECT_EQL(first ? NULL : nodes[i - 1], iter->previous); - EXPECT_EQL(last ? NULL : nodes[i + 1], iter->next); - } - break; - } - } -} -#define EXPECT_LIST_EQL(list, ...) \ - expect_list_eql(list, (dlist_node_t const *const[]){__VA_ARGS__}, sizeof((dlist_node_t *[]){__VA_ARGS__})); - -TEST(DLIST_EMPTY) { - - dlist_t list = DLIST_EMPTY; - - EXPECT_EQL(0, list.len); - EXPECT_EQL(NULL, list.head); - EXPECT_EQL(NULL, list.tail); -} - -TEST(dlist_append) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - EXPECT_EQL(0, list.len); - EXPECT_EQL(NULL, list.head); - EXPECT_EQL(NULL, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(NULL, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(NULL, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_append(&list, &node1); - - EXPECT_EQL(1, list.len); - EXPECT_EQL(&node1, list.head); - EXPECT_EQL(&node1, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(NULL, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(NULL, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_append(&list, &node2); - - EXPECT_EQL(2, list.len); - EXPECT_EQL(&node1, list.head); - EXPECT_EQL(&node2, list.tail); - - EXPECT_EQL(&node2, node1.next); - EXPECT_EQL(NULL, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(&node1, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_append(&list, &node3); - - EXPECT_EQL(3, list.len); - EXPECT_EQL(&node1, list.head); - EXPECT_EQL(&node3, list.tail); - - EXPECT_EQL(&node2, node1.next); - EXPECT_EQL(&node3, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(&node1, node2.previous); - EXPECT_EQL(&node2, node3.previous); -} - -TEST(dlist_prepend) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - EXPECT_EQL(0, list.len); - EXPECT_EQL(NULL, list.head); - EXPECT_EQL(NULL, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(NULL, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(NULL, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_prepend(&list, &node1); - - EXPECT_EQL(1, list.len); - EXPECT_EQL(&node1, list.head); - EXPECT_EQL(&node1, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(NULL, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(NULL, node1.previous); - EXPECT_EQL(NULL, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_prepend(&list, &node2); - - EXPECT_EQL(2, list.len); - EXPECT_EQL(&node2, list.head); - EXPECT_EQL(&node1, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(&node1, node2.next); - EXPECT_EQL(NULL, node3.next); - - EXPECT_EQL(&node2, node1.previous); - EXPECT_EQL(NULL, node2.previous); - EXPECT_EQL(NULL, node3.previous); - - dlist_prepend(&list, &node3); - - EXPECT_EQL(3, list.len); - EXPECT_EQL(&node3, list.head); - EXPECT_EQL(&node1, list.tail); - - EXPECT_EQL(NULL, node1.next); - EXPECT_EQL(&node1, node2.next); - EXPECT_EQL(&node2, node3.next); - - EXPECT_EQL(&node2, node1.previous); - EXPECT_EQL(&node3, node2.previous); - EXPECT_EQL(NULL, node3.previous); -} - -TEST(dlist_contains) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - EXPECT_FALSE(dlist_contains(&list, &node1)); - EXPECT_FALSE(dlist_contains(&list, &node2)); - EXPECT_FALSE(dlist_contains(&list, &node3)); - - dlist_append(&list, &node1); - - EXPECT_TRUE(dlist_contains(&list, &node1)); - EXPECT_FALSE(dlist_contains(&list, &node2)); - EXPECT_FALSE(dlist_contains(&list, &node3)); - - dlist_append(&list, &node2); - - EXPECT_TRUE(dlist_contains(&list, &node1)); - EXPECT_TRUE(dlist_contains(&list, &node2)); - EXPECT_FALSE(dlist_contains(&list, &node3)); - - dlist_append(&list, &node3); - - EXPECT_TRUE(dlist_contains(&list, &node1)); - EXPECT_TRUE(dlist_contains(&list, &node2)); - EXPECT_TRUE(dlist_contains(&list, &node3)); -} - -TEST(dlist_remove) { - // Tests for removing list mid - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3); - - dlist_remove(&list, &node2); - - EXPECT_LIST_EQL(list, &node1, &node3); - - dlist_remove(&list, &node1); - - EXPECT_LIST_EQL(list, &node3); - - dlist_remove(&list, &node3); - - EXPECT_LIST_EQL(list, ); -} - - -TEST(dlist_remove) { - // Tests for removing list HEAD - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3); - - dlist_remove(&list, &node1); - - EXPECT_LIST_EQL(list, &node2, &node3); -} - -TEST(dlist_remove) { - // Tests for removing list TAIL - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3); - - dlist_remove(&list, &node3); - - EXPECT_LIST_EQL(list, &node1, &node2); -} - -TEST(dlist_pop_front) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - dlist_node_t node4 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - dlist_append(&list, &node4); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3, &node4); - - EXPECT_EQL(&node1, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, &node2, &node3, &node4); - - EXPECT_EQL(&node2, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, &node3, &node4); - - EXPECT_EQL(&node3, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, &node4); - - EXPECT_EQL(&node4, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, ); - - EXPECT_EQL(NULL, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, ); - - EXPECT_EQL(NULL, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, ); -} - -TEST(dlist_pop_front) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - dlist_node_t node4 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - dlist_append(&list, &node4); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3, &node4); - - EXPECT_EQL(&node4, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3); - - EXPECT_EQL(&node3, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, &node1, &node2); - - EXPECT_EQL(&node2, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, &node1); - - EXPECT_EQL(&node1, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, ); - - EXPECT_EQL(NULL, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, ); - - EXPECT_EQL(NULL, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, ); -} - -TEST(dlist_pop_front, dlist_pop_front) { - dlist_t list = DLIST_EMPTY; - - dlist_node_t node1 = DLIST_NODE_EMPTY; - dlist_node_t node2 = DLIST_NODE_EMPTY; - dlist_node_t node3 = DLIST_NODE_EMPTY; - dlist_node_t node4 = DLIST_NODE_EMPTY; - dlist_node_t node5 = DLIST_NODE_EMPTY; - - dlist_append(&list, &node1); - dlist_append(&list, &node2); - dlist_append(&list, &node3); - dlist_append(&list, &node4); - dlist_append(&list, &node5); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3, &node4, &node5); - - EXPECT_EQL(&node5, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, &node1, &node2, &node3, &node4); - - EXPECT_EQL(&node1, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, &node2, &node3, &node4); - - EXPECT_EQL(&node4, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, &node2, &node3); - - EXPECT_EQL(&node2, dlist_pop_front(&list)); - - EXPECT_LIST_EQL(list, &node3); - - EXPECT_EQL(&node3, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, ); - - EXPECT_EQL(NULL, dlist_pop_back(&list)); - - EXPECT_LIST_EQL(list, ); -} diff --git a/test/proctest b/test/proctest deleted file mode 100755 index 797ae6b5fdcdecc303ea25bf6683a3557cf88306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 956 zcma)*&r94;5XUFcl~xp1JXq*ug#|s7)Qvw5y{&ayOJzN*rQqc?*@WFdb`z4fi!FuH zL%|*dsfWFl*7}cl@3H@acg5b@?-)iz(%T^No%!iWs#Z{rytvsXZ2@T^>Mxs~8CFEc43~t(S(CF5oleiM zgiFxeH2xm8vCP}0tdCU2>EhoM7L=a9<|+8wP^Hl`@XriC2Onm5GpB!@)7QbrkJ9%k z;=FgvMa3F@2CMUn=o^AhGV336`u!Xaa{N8FpPJ3>w!ONxYXnr@yYo7Q?Y6wGh-E~= z?K(-)wtPut2ir-AmLJ%bFT%jVX~r diff --git a/test/proctest.S b/test/proctest.S deleted file mode 100644 index 70782bf..0000000 --- a/test/proctest.S +++ /dev/null @@ -1,14 +0,0 @@ - - .global _start -_start: - la a0, _begin_str - la a1, _end_str - sub a1, a1, a0 - li a7, 0xff00 - ecall -halt: - j halt - -_begin_str: - .ascii "Hello, World!\r\n" -_end_str: diff --git a/test/text1 b/test/text1 deleted file mode 100644 index 8f1ffe5..0000000 --- a/test/text1 +++ /dev/null @@ -1 +0,0 @@ -Hi Ther. diff --git a/test/text2 b/test/text2 deleted file mode 100644 index 8f1ffe5..0000000 --- a/test/text2 +++ /dev/null @@ -1 +0,0 @@ -Hi Ther. diff --git a/test/unittest.h b/test/unittest.h deleted file mode 100644 index 980fc96..0000000 --- a/test/unittest.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "assertions.h" - -#include -#include -#include - -#define CONSTRUCTOR __attribute__((constructor)) -#define TEST_DECL(X) \ - static void unittest_##X(void) CONSTRUCTOR; \ - static void unittest_##X(void) -#define TEST_DECL_WRAP(X) TEST_DECL(X) -#define TEST(...) TEST_DECL_WRAP(__COUNTER__) - -#define EXPECT(expected) assert_always(expected) -#define EXPECT_EQL(expected, actual) assert_always((expected) == (actual)) -#define EXPECT_TRUE(expected) assert_always((expected) == true) -#define EXPECT_FALSE(expected) assert_always((expected) == false) - -int main() { - return 0; -} - -void kernel_assertion_failure(char const *assertion_msg) { - fprintf(stderr, "ASSERTION FAILED: %s", assertion_msg); - abort(); -} diff --git a/test/userlandlib.c b/test/userlandlib.c deleted file mode 100644 index 26411c1..0000000 --- a/test/userlandlib.c +++ /dev/null @@ -1,5 +0,0 @@ - -void exit(int code) { - while (1) - ; -} diff --git a/test/userlandlib.so b/test/userlandlib.so deleted file mode 100755 index d7a0e02739a1916341da30ce5ece6c6221eac857..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5344 zcmeHLOHWf#5S~kmsJtHw6Bge13M6_11vj$LwzNPj4+|_zOl~f1r8V5PX>Um(1dVRG zbmiIwzr-Kl%D>JCTY6+d24z4ZBGu6$GeU%Mq$rqU&3M{K-(Vnj6JQ+utwHc@%?H5bYhe1jAUgd` zU^4w&W9@s8|Ab+prgFRr9DfezbS9PGWUj4%wd?A^9Voyxk z(=$%YnUeSnhSy5<+^$%YP@_ZLwcVLmDOR0!{aAI%^{C~j?fZUXXSzCd`FcDLDWa-b z5uQt9R?+%g8nfEg=hc|m(6zG0y4q&FuQ4+ra&(4uHh30N#AL-*5SZCHr-;gCC+}oPKznM+BnWdHI@r9JT5l>`NuDI^P%BGuIbko`R za>`wt&x*T{Sxv+hsu3Yhea{cPEy$pzWzlHc<%U!A>P2z#du4=a8PvoH z3e7;ALeYI)^ZbHa%)@4oit_wYPMqxuqH-1AFO;FE+vRvcP%CXUfEdP01c=54~P z2qs03@ukii%HP-g#>$Bg=OppIFpjvhj|HemzW|XXAQQ*?PVRheCT<;ZT$6iLeKlNQ z_RNf*lK&O2z?@Iz%Z7r(nHV6Y6MJCBnYE&bR?q>V8oN^^GN sMZ`UWu^;*TB51|TWF|kFKPMA^R+pEVF*ESyhnbf$ zEu}RT)J4&Xpl&M&SqVz$&V?wFg}4!+o8l&d+akKt@%!GL8>g+HuH4KaXU;kIoO|xQ z=e~QwIoFblvzBFvfe!gaD6Mu_G6j0!n1u3_IC4aW<+vP^Ll~!S3L2t=3B*o}5p7@^ zavFY#ry&!m!!Y%g(Fm9(&=)03WkL+=Kixko%$@=J)A$ zAQP$Q8mm7A**c8sI3p2943RqGi_n8S1f0)pr=V|L-}vWT?rqdBY>fKZ5x-E{s*h9) zwamrIiIIX|nVfKIWp^AVCJy0VDHAxCd)KEH3C}C`wi!Qlwdbwpu6}TZwykiS!Z5A4 zzk3aG(>NF5D1UPGLLghUT-EnVS!@ow5T!Q#@`mTDO1V%9a@BJpCml<=xPcb<@T|zB z{Z-8V)c$eMp85U#>!53A<&BTyvMK#?!o_{M@7&$A`(+UGV$nn2ocUV12fLi5AD*)0 z^XW5*n05X2`JC^UpKx9-SN-g1*jYpNGmIs7d8g5641-c8*q2jcU9qg8z7D~*#p!-SYgG@x9)TNW7nlHnbzqjzBvC?Fh6Z(2hVm0__O2BhZdOI|Bbt z1X$OYdb5ri_}4!g<(r_a>GnaX+Xd|beH{1*ko8Yk%Ym|nj-Vc6Io1ngjd~b(f--75 z@}%9Qz#~lx@}D4`FVr0Tc}~^~JQ0*x4LWe(oAveF%*@ly@Ofu^(w%U}BsK|MSka1g z9&Bf%tBT^bFi{y-#fi$8^2lY#T`m^4{PD^dy*&)<3lQwE0z@r-AnO8@vC?`*LdQzW ztg>|swXCaT#zM=Ctlqzt87bY*&@v+?l0UF#%XH=}zEq;?o>FpgQT zkHg_zk=m$<3C@8Yjfxhq52{=}XiHSICoOlPe&=_<{)+~^-=={6#JvXZfOkW%u%8Q{ zye};umY2Y=uc4tw3Sb^>?#IIZu2Ip_FL)24*>42;+mN|F>+PfX!frM74ro*cB^J+E~ zTS}_=L`u}$;z~TWs8(iY*OKYK3?J;AD7BV|rDH0doLg8{N;YaWxQnl?spN73vQijP zwZN+e;O{e4x$xboTq&#DG}W?xh;HptG4M9Ttp!z0^M(uiH5G9;OIvQ{a&`PRow~Wadaddeb1I*Om65`EUa^n?!zAEtmNAEia5Lp%F;}7o zcClP92&#pREyNvH@vmVBmi!v|vUN{T_XCXs^QAHm@-@?r`JfI3zd`-tH6@Rhl>F9c zlxfF2aT9jz6Fq1*f-$~c+A-Je!j9>PYj924^Q}DzWR{^FbMrow+=~I)5}pNeP8`U5 z(~Akry&U7WNlKY|&S56vyL4dJng+QhaSmwg_}*4w7xuU?PJkG~5`Jk%neQMEMrWB& z9j;4m9cb)yZ&Ux@&{leXFkm?s<GXL+O@7r9r0Zt zd{vre!rrs#IdhCQ1X2@o%30X)P6olB0&-mph5u{Avw|n=B1!FQHvBdIqL5ncK7ylL He`EJ2K3F%( diff --git a/test/userlandtest.c b/test/userlandtest.c deleted file mode 100644 index 0e49033..0000000 --- a/test/userlandtest.c +++ /dev/null @@ -1,10 +0,0 @@ - -extern void exit(int code); - -char const rodata[] = "Hello, World!"; -char data[] = "This is a data"; -char bss[32]; - -void _start() { - exit(1234); -} diff --git a/tools/address-filter.py b/tools/address-filter.py index e6002b1..79d32f4 100755 --- a/tools/address-filter.py +++ b/tools/address-filter.py @@ -8,7 +8,7 @@ if len(sys.argv) > 1: file_name = sys.argv[1] -matcher = re.compile("(0x[0-9A-Za-z]{8})") +matcher = re.compile("(0x[0-9A-Fa-f]{8})") def runAndCapture(cmd): diff --git a/tools/ramfs-gen.py b/tools/ramfs-gen.py index ae15342..07e68d7 100755 --- a/tools/ramfs-gen.py +++ b/tools/ramfs-gen.py @@ -71,6 +71,7 @@ def add_dir(path, virtpath): outfd.write(" fileoff_t len;\n") outfd.write(dirs) outfd.write(files) +outfd.write(" (void)len;\n") outfd.write("}\n") outfd.write("// NOLINTEND\n") outfd.flush() diff --git a/tools/readjal.py b/tools/readjal.py deleted file mode 100755 index 11362f9..0000000 --- a/tools/readjal.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 - -import sys - - - -def read_jal(raw): - u32 = ((raw >> 20) & 0x0000_07fe) - u32 |= ((raw >> 9) & 0x0000_0800) - u32 |= ((raw) & 0x000f_f000) - u32 |= ((raw >> 11) & 0x0010_0000) - s32 = (u32 | 0xffe0_0000) if (raw & 0x8000_0000) else u32 - return s32 - - - -if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: readjal.py [instruction...]") - for i in range(1, len(sys.argv)): - n=read_jal(int(sys.argv[i], base=16)) - print(hex(n))