diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CMakeLists.txt | 19 | ||||
| -rw-r--r-- | LICENSE | 9 | ||||
| -rw-r--r-- | README.md | 18 | ||||
| -rw-r--r-- | include/uart.h | 30 | ||||
| -rw-r--r-- | mise.toml | 2 | ||||
| -rw-r--r-- | src/crt0.S | 70 | ||||
| -rw-r--r-- | src/syscalls.c | 103 |
8 files changed, 253 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..230aa58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +config/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f00d15f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) + +project(libtrv LANGUAGES C ASM) + +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mcmodel=medany -march=rv64im -mabi=lp64") + +set(SRC_FILES + src/syscalls.c + src/crt0.S +) + +include_directories(include) + +add_library(trv STATIC ${SRC_FILES}) + +install(TARGETS trv DESTINATION lib) +install(DIRECTORY include/ DESTINATION include/trv) @@ -0,0 +1,9 @@ +Copyright 2025-2026 taitep + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..80e7f80 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# libtrv + +Newlib port stuff for trve. + +## Usage + +Compile your program with `-nostdlib` and `-march=rv64im -mabi=lp64 -mcmodel=medany`, and +manually linked to the newlib libc and libtrv itself, using the linker script +from the TRVE repository. Do NOT use a crt0 from outside libtrv (which includes one) and make +sure newlib is built with newlib provided syscalls disabled and you do not link libgloss. +Also, the linking with newlib and libtrv should be in a group, as there are crossing dependencies +between the 2. + +## Build process + +libtrv is built with cmake. You will need a cmake toolchain configuration file, which should define a C compiler and potentially an install prefix. + +The libtrv library will be installed under the lib directory of the prefix, and headers under include/trv. diff --git a/include/uart.h b/include/uart.h new file mode 100644 index 0000000..76f4b34 --- /dev/null +++ b/include/uart.h @@ -0,0 +1,30 @@ +#pragma once + +#define UART_BASE 0x10000 +#define UART_DATA *(volatile char *)(UART_BASE + 0) +#define UART_STATUS *(volatile char *)(UART_BASE + 1) +#define UART_TX_READY 0b01 +#define UART_RX_READY 0b10 + +static inline int uart_rx_ready() { return (UART_STATUS & UART_RX_READY) != 0; } +static inline int uart_tx_ready() { return (UART_STATUS & UART_TX_READY) != 0; } + +static inline void uart_putc(char c) { + while (!uart_tx_ready()) + ; + UART_DATA = c; +} + +static inline void uart_puts(const char *s) { + while (*s) { + uart_putc(*s++); + } +} + +static inline char uart_getc_nonblocking() { return UART_DATA; } + +static inline char uart_getc() { + while (!uart_rx_ready()) + ; + return UART_DATA; +} diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..0d015e7 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +cmake = "latest" diff --git a/src/crt0.S b/src/crt0.S new file mode 100644 index 0000000..97228c1 --- /dev/null +++ b/src/crt0.S @@ -0,0 +1,70 @@ +# vim: filetype=asm: +/* Copyright (c) 2017 SiFive Inc. All rights reserved. + + This copyrighted material is made available to anyone wishing to use, + modify, copy, or redistribute it subject to the terms and conditions + of the FreeBSD License. This program is distributed in the hope that + it will be useful, but WITHOUT ANY WARRANTY expressed or implied, + including the implied warranties of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. A copy of this license is available at + http://www.opensource.org/licenses. + + Modified in 2026 by taitep to run bare metal on the TRVE emulator, +*/ + +#include "newlib.h" + +#========================================================================= +# crt0.S : Entry point for RISC-V user programs +#========================================================================= + + .text + .global _start, _exit, _heap_end + .type _start, @function +_start: + # Initialize the stack pointer + la sp, _stack_top + + # Initialize global pointer +.option push +.option norelax +1:auipc gp, %pcrel_hi(__global_pointer$) + addi gp, gp, %pcrel_lo(1b) +.option pop + + # Clear the bss segment + la a0, _bss_start + la a2, _bss_end + sub a2, a2, a0 + li a1, 0 + call memset + + # Clear the sbss segment + la a0, _sbss_start + la a2, _sbss_end + sub a2, a2, a0 + li a1, 0 + call memset + +#ifdef _LITE_EXIT + # Make reference to atexit weak to avoid unconditionally pulling in + # support code. Refer to comments in __atexit.c for more details. + .weak atexit + la a0, atexit + beqz a0, .Lweak_atexit + .weak __libc_fini_array +#endif + + la a0, __libc_fini_array # Register global termination functions + call atexit # to be called upon exit +#ifdef _LITE_EXIT +.Lweak_atexit: +#endif + call __libc_init_array # Run global initialization functions + + call main + call exit +_exit: j _exit + .size _start, .-_start +_heap_end: + .dword _heap_start diff --git a/src/syscalls.c b/src/syscalls.c new file mode 100644 index 0000000..443c9cd --- /dev/null +++ b/src/syscalls.c @@ -0,0 +1,103 @@ +#include "uart.h" + +#include <sys/stat.h> +#include <sys/times.h> +#include <sys/types.h> + +#include <errno.h> +#undef errno +extern int errno; + +// defined in crt0.S +void _exit(int c); + +int _close(int file) { return -1; } + +char *__env[1] = {0}; +char **environ = __env; + +int _execve(char *name, char **argv, char **env) { + errno = ENOMEM; + return -1; +} + +int _fork(void) { + errno = EAGAIN; + return -1; +} + +int _fstat(int file, struct stat *st) { + st->st_mode = S_IFCHR; + return 0; +} + +int _getpid(void) { return 1; } +int _isatty(int file) { return 1; } + +int _link(char *old, char *new) { + errno = EMLINK; + return -1; +} + +int _lseek(int file, int ptr, int dir) { return 0; } + +int _open(const char *name, int flags, int mode) { return -1; } + +int _read(int file, char *buf, int len) { + while (!uart_rx_ready()) + ; + + int i; + for (i = 0; i < len; i++) { + if (!uart_rx_ready()) { + break; + } + buf[i] = uart_getc_nonblocking(); + } + return i; +} + +void *_sbrk(int incr) { + extern void _heap_start; + extern void *_heap_end; + void *prev_heap_end = _heap_end; + + void *stack_ptr; + __asm__ volatile("mv %0, sp" : "=r"(stack_ptr)); + if (_heap_end + incr > stack_ptr) { + uart_puts("Heap and stack collision\n"); + _exit(1); + } + + _heap_end += incr; + return prev_heap_end; +} + +int _stat(const char *__restrict file, struct stat *__restrict st) { + st->st_mode = S_IFCHR; + return 0; +} + +clock_t _times(struct tms *buf) { return (clock_t)-1; } + +int _unlink(char *name) { + errno = ENOENT; + return -1; +} + +int _wait(int *status) { + errno = ECHILD; + return -1; +} + +int _write(int file, char *buf, int len) { + for (int i = 0; i < len; i++) { + uart_putc(buf[i]); + } + return len; +} + +int _kill(int pid, int sig) { + errno = EINVAL; + return -1; +} |
