From 00fc82f17cff9295387d516384ecdc443acb1b22 Mon Sep 17 00:00:00 2001 From: Bradley Morgan Date: Sat, 3 Oct 2026 18:57:38 +0000 Subject: tashaboot: arm64 bringup, semihosting payload loader consoles on the pl011 the dtb points at, walks the memory node and chosen, loads an arm64 kernel Image over semihosting and jumps to it with the documented register state. string functions, printf and libfdt are vendored from lk (lk2nd) and u-boot so the libc surface is the one those projects already proved. built and booted on qemu virt, payload exits clean through semihosting. --- include/assert.h | 41 +++++++++++++ include/boot.h | 56 +++++++++++++++++ include/compiler.h | 133 +++++++++++++++++++++++++++++++++++++++++ include/ctype.h | 43 +++++++++++++ include/debug.h | 109 +++++++++++++++++++++++++++++++++ include/drivers/serial/pl011.h | 51 ++++++++++++++++ include/endian.h | 54 +++++++++++++++++ include/limits.h | 121 +++++++++++++++++++++++++++++++++++++ include/platform/debug.h | 44 ++++++++++++++ include/printf.h | 53 ++++++++++++++++ include/reg.h | 50 ++++++++++++++++ include/semihosting.h | 31 ++++++++++ include/stdio.h | 51 ++++++++++++++++ include/string.h | 69 +++++++++++++++++++++ include/sys/types.h | 86 ++++++++++++++++++++++++++ 15 files changed, 992 insertions(+) create mode 100644 include/assert.h create mode 100644 include/boot.h create mode 100644 include/compiler.h create mode 100644 include/ctype.h create mode 100644 include/debug.h create mode 100644 include/drivers/serial/pl011.h create mode 100644 include/endian.h create mode 100644 include/limits.h create mode 100644 include/platform/debug.h create mode 100644 include/printf.h create mode 100644 include/reg.h create mode 100644 include/semihosting.h create mode 100644 include/stdio.h create mode 100644 include/string.h create mode 100644 include/sys/types.h (limited to 'include') diff --git a/include/assert.h b/include/assert.h new file mode 100644 index 0000000..ecdfaca --- /dev/null +++ b/include/assert.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __ASSERT_H +#define __ASSERT_H + +#include +#include + +#define ASSERT(x) \ + do { if (unlikely(!(x))) { panic("ASSERT FAILED at (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0) +#define assert(x) ASSERT(x) + +#if DEBUGLEVEL > 1 +#define DEBUG_ASSERT(x) \ + do { if (unlikely(!(x))) { panic("DEBUG ASSERT FAILED at (%s:%d): %s\n", __FILE__, __LINE__, #x); } } while (0) +#else +#define DEBUG_ASSERT(x) \ + do { } while(0) +#endif + +#endif diff --git a/include/boot.h b/include/boot.h new file mode 100644 index 0000000..34bfa88 --- /dev/null +++ b/include/boot.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BOOT_H +#define __BOOT_H + +#include +#include + +/* + * payload loading and the arm64 boot protocol. See Documentation/ + * arch/arm64/booting.rst in the kernel tree for the register contract + * we honour when jumping. + */ + +#define LINUX_ARM64_IMAGE_MAGIC 0x644d5241 + +/* the 64 byte header every arm64 kernel Image starts with */ +struct Image_header { + uint32_t code0; /* Executable code */ + uint32_t code1; /* Executable code */ + uint64_t text_offset; /* Image load offset, LE */ + uint64_t image_size; /* Effective Image size, LE */ + uint64_t flags; /* Kernel flags, LE */ + uint64_t res2; /* reserved */ + uint64_t res3; /* reserved */ + uint64_t res4; /* reserved */ + uint32_t magic; /* Magic number */ + uint32_t res5; +}; + +struct tb_image { + uintptr_t ep; /* entry point to jump to */ + uint64_t size; /* image size in bytes */ + uintptr_t load; /* address the image was placed at */ +}; + +/* + * validate the header at image and work out where it wants to live. + * returns 0 and fills img on success, negative on a bad image. + */ +int tb_image_setup(uintptr_t image, uintptr_t mem_base, uint32 mem_size, + struct tb_image *img); + +/* + * load the payload from semihosting into mem_base. returns 0 and fills + * img, negative when there is no debugger or no file. + */ +int tb_load_semihosting(const char *fname, uintptr_t load_addr, + uintptr_t mem_base, uint32 mem_size, + struct tb_image *img); + +/* + * jump to the kernel: x0 = dtb, x1 = x2 = x3 = 0. never returns. + */ +void __NO_RETURN tb_boot_linux(uintptr_t ep, const void *dtb); + +#endif diff --git a/include/compiler.h b/include/compiler.h new file mode 100644 index 0000000..e659047 --- /dev/null +++ b/include/compiler.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __COMPILER_H +#define __COMPILER_H + +#ifndef __ASSEMBLY__ + +#if __GNUC__ +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define __USED __attribute__((__used__)) +#define __UNUSED __attribute__((__unused__)) +#define __PACKED __attribute__((packed)) +#define __ALIGNED(x) __attribute__((aligned(x))) +#define __PRINTFLIKE(__fmt,__varargs) __attribute__((__format__ (__printf__, __fmt, __varargs))) +#define __SCANFLIKE(__fmt,__varargs) __attribute__((__format__ (__scanf__, __fmt, __varargs))) +#define __SECTION(x) __attribute((section(x))) +#define __PURE __attribute((pure)) +#define __CONST __attribute((const)) +#define __NO_RETURN __attribute__((noreturn)) +#define __MALLOC __attribute__((malloc)) +#define __WEAK __attribute__((weak)) +#define __GNU_INLINE __attribute__((gnu_inline)) +#define __GET_CALLER(x) __builtin_return_address(0) +#define __GET_FRAME(x) __builtin_frame_address(0) + +#define INCBIN(symname, sizename, filename, section) \ + __asm__ (".section " section "; .align 4; .globl "#symname); \ + __asm__ (""#symname ":\n.incbin \"" filename "\""); \ + __asm__ (".section " section "; .align 1;"); \ + __asm__ (""#symname "_end:"); \ + __asm__ (".section " section "; .align 4; .globl "#sizename); \ + __asm__ (""#sizename ": .long "#symname "_end - "#symname " - 1"); \ + extern unsigned char symname[]; \ + extern unsigned int sizename + +#define INCFILE(symname, sizename, filename) INCBIN(symname, sizename, filename, ".rodata") + +/* look for gcc 3.0 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 0) +#define __ALWAYS_INLINE __attribute__((always_inline)) +#else +#define __ALWAYS_INLINE +#endif + +/* look for gcc 3.1 and above */ +#if !defined(__DEPRECATED) // seems to be built in in some versions of the compiler +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define __DEPRECATED __attribute((deprecated)) +#else +#define __DEPRECATED +#endif +#endif + +/* look for gcc 3.3 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) +/* the may_alias attribute was introduced in gcc 3.3; before that, there + * was no way to specify aliasiang rules on a type-by-type basis */ +#define __MAY_ALIAS __attribute__((may_alias)) + +/* nonnull was added in gcc 3.3 as well */ +#define __NONNULL(x) __attribute((nonnull x)) +#else +#define __MAY_ALIAS +#define __NONNULL(x) +#endif + +/* look for gcc 3.4 and above */ +#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __WARN_UNUSED_RESULT __attribute((warn_unused_result)) +#else +#define __WARN_UNUSED_RESULT +#endif + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) +#define __EXTERNALLY_VISIBLE __attribute__((externally_visible)) +#else +#define __EXTERNALLY_VISIBLE +#endif + +#else + +#define likely(x) (x) +#define unlikely(x) (x) +#define __USED +#define __UNUSED +#define __PACKED +#define __ALIGNED(x) +#define __PRINTFLIKE(__fmt,__varargs) +#define __SCANFLIKE(__fmt,__varargs) +#define __SECTION(x) +#define __PURE +#define __CONST +#define __NONNULL(x) +#define __DEPRECATED +#define __WARN_UNUSED_RESULT +#define __ALWAYS_INLINE +#define __MAY_ALIAS +#define __NO_RETURN +#endif + +#endif + +/* TODO: add type check */ +#define countof(a) (sizeof(a) / sizeof((a)[0])) + +#define IS_ENABLED(define) _IS_ENABLED(define) +#define _comma_if_enabled_1 , +#define _IS_ENABLED(value) __IS_ENABLED(_comma_if_enabled_##value) +#define __IS_ENABLED(comma) ___IS_ENABLED(comma 1, 0) +#define ___IS_ENABLED(_, enabled, ...) enabled + +#endif diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..7f9982e --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __CTYPE_H +#define __CTYPE_H + +int isalnum(int c); +int isalpha(int c); +int isblank(int c); +int iscntrl(int c); +int isdigit(int c); +int isgraph(int c); +int islower(int c); +int isprint(int c); +int ispunct(int c); +int isspace(int c); +int isupper(int c); +int isxdigit(int c); + +int tolower(int c); +int toupper(int c); + +#endif + diff --git a/include/debug.h b/include/debug.h new file mode 100644 index 0000000..83b62b2 --- /dev/null +++ b/include/debug.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(DEBUG) +#define DEBUGLEVEL DEBUG +#else +#define DEBUGLEVEL 2 +#endif + +/* debug levels */ +#define CRITICAL 0 +#define ALWAYS 0 +#define INFO 1 +#define SPEW 2 + +/* output */ +void _dputc(char c); // XXX for now, platform implements +int _dputs(const char *str); +int _dprintf(const char *fmt, ...) __PRINTFLIKE(1, 2); +int _dvprintf(const char *fmt, va_list ap); + +#define dputc(level, str) do { if ((level) <= DEBUGLEVEL) { _dputc(str); } } while (0) +#define dputs(level, str) do { if ((level) <= DEBUGLEVEL) { _dputs(str); } } while (0) +#define dprintf(level, x...) do { if ((level) <= DEBUGLEVEL) { _dprintf(x); } } while (0) +#define dvprintf(level, x...) do { if ((level) <= DEBUGLEVEL) { _dvprintf(x); } } while (0) + +/* input */ +int dgetc(char *c, bool wait); + +/* systemwide halts */ +void halt(void); + +void dump_frame(void *frame); + +void _panic(void *caller, const char *fmt, ...) __PRINTFLIKE(2, 3); +#define panic(x...) _panic(__GET_CALLER(), x) + +#define PANIC_UNIMPLEMENTED panic("%s unimplemented\n", __PRETTY_FUNCTION__) + +extern uintptr_t __stack_chk_guard; + +/* +* Initialize the stack protector canary value. +*/ +#define __stack_chk_guard_setup() do { __stack_chk_guard = get_canary(); } while(0) + +void __attribute__ ((noreturn)) + __stack_chk_fail (void); + +/* spin the cpu for a period of (short) time */ +void spin(uint32_t usecs); + +/* dump memory */ +void hexdump(const void *ptr, size_t len); +void hexdump8(const void *ptr, size_t len); + +/* trace routines */ +#define TRACE_ENTRY printf("%s: entry\n", __PRETTY_FUNCTION__) +#define TRACE_EXIT printf("%s: exit\n", __PRETTY_FUNCTION__) +#define TRACE_ENTRY_OBJ printf("%s: entry obj %p\n", __PRETTY_FUNCTION__, this) +#define TRACE_EXIT_OBJ printf("%s: exit obj %p\n", __PRETTY_FUNCTION__, this) +#define TRACE printf("%s:%d\n", __PRETTY_FUNCTION__, __LINE__) +#define TRACEF(x...) do { printf("%s:%d: ", __PRETTY_FUNCTION__, __LINE__); printf(x); } while (0) + +/* trace routines that work if LOCAL_TRACE is set */ +#define LTRACE_ENTRY do { if (LOCAL_TRACE) { TRACE_ENTRY; } } while (0) +#define LTRACE_EXIT do { if (LOCAL_TRACE) { TRACE_EXIT; } } while (0) +#define LTRACE do { if (LOCAL_TRACE) { TRACE; } } while (0) +#define LTRACEF(x...) do { if (LOCAL_TRACE) { TRACEF(x); } } while (0) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drivers/serial/pl011.h b/include/drivers/serial/pl011.h new file mode 100644 index 0000000..71ffc5a --- /dev/null +++ b/include/drivers/serial/pl011.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * pl011.h - PL010/PL011 register defs, shared struct like u-boot + * + * Copyright (C) 2026 Bradley Morgan + */ + +#ifndef _DRIVERS_SERIAL_PL011_H +#define _DRIVERS_SERIAL_PL011_H + +#include +#include + +/* + * the PL010 and PL011 overlap in the common registers so one struct + * covers both, same trick as u-boot's serial_pl01x.c + */ +struct pl01x_regs { + uint32 dr; /* 0x00 Data register */ + uint32 ecr; /* 0x04 Error clear register (Write) */ + uint32 pl010_lcrh; /* 0x08 Line control, high byte */ + uint32 pl010_lcrm; /* 0x0C Line control, middle byte */ + uint32 pl010_lcrl; /* 0x10 Line control, low byte */ + uint32 pl010_cr; /* 0x14 Control register */ + uint32 fr; /* 0x18 Flag register (Read only) */ + uint32 reserved; /* 0x1C */ + uint32 ilpr; /* 0x20 IrDA low-power counter */ + uint32 pl011_ibrd; /* 0x24 Integer baud rate divisor */ + uint32 pl011_fbrd; /* 0x28 Fractional baud rate divisor */ + uint32 pl011_lcrh; /* 0x2C Line control register */ + uint32 pl011_cr; /* 0x30 Control register */ + uint32 pl011_ifls; /* 0x34 Interrupt FIFO level select */ + uint32 pl011_imsc; /* 0x38 Interrupt mask set/clear */ + uint32 pl011_ris; /* 0x3C Raw interrupt status */ + uint32 pl011_mis; /* 0x40 Masked interrupt status */ + uint32 pl011_icr; /* 0x44 Interrupt clear register */ +}; + +#define UART_PL01x_FR_TXFE 0x80 +#define UART_PL01x_FR_RXFF 0x40 +#define UART_PL01x_FR_TXFF 0x20 +#define UART_PL01x_FR_RXFE 0x10 +#define UART_PL01x_FR_BUSY 0x08 +#define UART_PL01x_FR_TMSK (UART_PL01x_FR_TXFF + UART_PL01x_FR_BUSY) + +/* drivers/serial/pl011.c */ +void pl011_init(uintptr_t base, uint32 clock, uint32 baud); +void pl011_putc(uintptr_t base, char c); +int pl011_getc(uintptr_t base); + +#endif diff --git a/include/endian.h b/include/endian.h new file mode 100644 index 0000000..42f880c --- /dev/null +++ b/include/endian.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * endian.h - byte order swaps. arm64 and ppc64le are both little + * endian, so the macros compile to nothing there, but the big endian + * fallbacks stay so a BE target builds without a rewrite. + * + * Copyright (C) 2026 Bradley Morgan + */ + +#ifndef __ENDIAN_H +#define __ENDIAN_H + +#include + +static inline uint16_t __swap16(uint16_t x) +{ + return (uint16_t)((x << 8) | (x >> 8)); +} + +static inline uint32_t __swap32(uint32_t x) +{ + return ((x << 24) | + ((x & 0xff00) << 8) | + ((x & 0xff0000) >> 8) | + (x >> 24)); +} + +static inline uint64_t __swap64(uint64_t x) +{ + return ((uint64_t)__swap32((uint32_t)x) << 32) | + __swap32((uint32_t)(x >> 32)); +} + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#define le16_to_cpu(x) __swap16(x) +#define le32_to_cpu(x) __swap32(x) +#define le64_to_cpu(x) __swap64(x) +#define cpu_to_le16(x) __swap16(x) +#define cpu_to_le32(x) __swap32(x) +#define cpu_to_le64(x) __swap64(x) + +#else + +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define cpu_to_le64(x) (x) + +#endif + +#endif diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 0000000..ec83068 --- /dev/null +++ b/include/limits.h @@ -0,0 +1,121 @@ +/* This administrivia gets added to the beginning of limits.h + if the system has its own version of limits.h. */ + +/* We use _GCC_LIMITS_H_ because we want this not to match + any macros that the system's limits.h uses for its own purposes. */ +#ifndef _GCC_LIMITS_H_ /* Terminated in limity.h. */ +#define _GCC_LIMITS_H_ + +#ifndef _LIMITS_H___ +#define _LIMITS_H___ + +/* Number of bits in a `char'. */ +#undef CHAR_BIT +#define CHAR_BIT __CHAR_BIT__ + +/* Maximum length of a multibyte character. */ +#ifndef MB_LEN_MAX +#define MB_LEN_MAX 1 +#endif + +/* Minimum and maximum values a `signed char' can hold. */ +#undef SCHAR_MIN +#define SCHAR_MIN (-SCHAR_MAX - 1) +#undef SCHAR_MAX +#define SCHAR_MAX __SCHAR_MAX__ + +/* Maximum value an `unsigned char' can hold. (Minimum is 0). */ +#undef UCHAR_MAX +#if __SCHAR_MAX__ == __INT_MAX__ +# define UCHAR_MAX (SCHAR_MAX * 2U + 1U) +#else +# define UCHAR_MAX (SCHAR_MAX * 2 + 1) +#endif + +/* Minimum and maximum values a `char' can hold. */ +#ifdef __CHAR_UNSIGNED__ +# undef CHAR_MIN +# if __SCHAR_MAX__ == __INT_MAX__ +# define CHAR_MIN 0U +# else +# define CHAR_MIN 0 +# endif +# undef CHAR_MAX +# define CHAR_MAX UCHAR_MAX +#else +# undef CHAR_MIN +# define CHAR_MIN SCHAR_MIN +# undef CHAR_MAX +# define CHAR_MAX SCHAR_MAX +#endif + +/* Minimum and maximum values a `signed short int' can hold. */ +#undef SHRT_MIN +#define SHRT_MIN (-SHRT_MAX - 1) +#undef SHRT_MAX +#define SHRT_MAX __SHRT_MAX__ + +/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */ +#undef USHRT_MAX +#if __SHRT_MAX__ == __INT_MAX__ +# define USHRT_MAX (SHRT_MAX * 2U + 1U) +#else +# define USHRT_MAX (SHRT_MAX * 2 + 1) +#endif + +/* Minimum and maximum values a `signed int' can hold. */ +#undef INT_MIN +#define INT_MIN (-INT_MAX - 1) +#undef INT_MAX +#define INT_MAX __INT_MAX__ + +/* Maximum value an `unsigned int' can hold. (Minimum is 0). */ +#undef UINT_MAX +#define UINT_MAX (INT_MAX * 2U + 1U) + +/* Minimum and maximum values a `signed long int' can hold. + (Same as `int'). */ +#undef LONG_MIN +#define LONG_MIN (-LONG_MAX - 1L) +#undef LONG_MAX +#define LONG_MAX __LONG_MAX__ + +/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */ +#undef ULONG_MAX +#define ULONG_MAX (LONG_MAX * 2UL + 1UL) + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* Minimum and maximum values a `signed long long int' can hold. */ +# undef LLONG_MIN +# define LLONG_MIN (-LLONG_MAX - 1LL) +# undef LLONG_MAX +# define LLONG_MAX __LONG_LONG_MAX__ + +/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ +# undef ULLONG_MAX +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +#endif + +#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__) +/* Minimum and maximum values a `signed long long int' can hold. */ +# undef LONG_LONG_MIN +# define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL) +# undef LONG_LONG_MAX +# define LONG_LONG_MAX __LONG_LONG_MAX__ + +/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ +# undef ULONG_LONG_MAX +# define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL) +#endif + +#endif /* _LIMITS_H___ */ +/* This administrivia gets added to the end of limits.h + if the system has its own version of limits.h. */ + +#else /* not _GCC_LIMITS_H_ */ + +#ifdef _GCC_NEXT_LIMITS_H +#include_next /* recurse down to the real one */ +#endif + +#endif /* not _GCC_LIMITS_H_ */ diff --git a/include/platform/debug.h b/include/platform/debug.h new file mode 100644 index 0000000..38f30a7 --- /dev/null +++ b/include/platform/debug.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * Copyright (c) 2026 Bradley Morgan + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __PLATFORM_DEBUG_H +#define __PLATFORM_DEBUG_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +int _dprintf(const char *fmt, ...) __PRINTFLIKE(1, 2); +int _dvprintf(const char *fmt, va_list ap); + +void platform_halt(void); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/printf.h b/include/printf.h new file mode 100644 index 0000000..92981df --- /dev/null +++ b/include/printf.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __LIB_PRINTF_H +#define __LIB_PRINTF_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +int printf(const char *fmt, ...); +int sprintf(char *str, const char *fmt, ...) __PRINTFLIKE(2, 3); +int snprintf(char *str, size_t len, const char *fmt, ...) __PRINTFLIKE(3, 4); +int vsprintf(char *str, const char *fmt, va_list ap); +int vsnprintf(char *str, size_t len, const char *fmt, va_list ap); + +/* printf engine that parses the format string and generates output */ + +/* function pointer to pass the engine, + * return code is remaining characters in destination (or INT_MAX for infinity) + */ +typedef int (*_printf_engine_output_func)(char c, void *state); + +int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/reg.h b/include/reg.h new file mode 100644 index 0000000..321074b --- /dev/null +++ b/include/reg.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * reg.h - mmio accessors. ld/st straight to the device, nothing cute. + * + * Copyright (C) 2026 Bradley Morgan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __REG_H +#define __REG_H + +#include +#include + +#define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr)) + +static inline void writel(uint32_t v, volatile void *addr) +{ + *(volatile uint32_t *)addr = v; +} + +static inline uint32_t readl(const volatile void *addr) +{ + return *(const volatile uint32_t *)addr; +} + +static inline void writew(uint16_t v, volatile void *addr) +{ + *(volatile uint16_t *)addr = v; +} + +static inline uint16_t readw(const volatile void *addr) +{ + return *(const volatile uint16_t *)addr; +} + +static inline void writeb(uint8_t v, volatile void *addr) +{ + *(volatile uint8_t *)addr = v; +} + +static inline uint8_t readb(const volatile void *addr) +{ + return *(const volatile uint8_t *)addr; +} + +#endif diff --git a/include/semihosting.h b/include/semihosting.h new file mode 100644 index 0000000..2f8c8f2 --- /dev/null +++ b/include/semihosting.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SEMIHOSTING_H +#define __SEMIHOSTING_H + +#include + +/* + * semihosting file io, backed by the host when qemu runs with + * -semihosting. all calls return negative errno style errors so the + * boot flow can fall back to whatever the board has without semihosting. + */ + +enum smh_open_mode { + MODE_READ = 0x0, + MODE_BINARY = 0x1, + MODE_PLUS = 0x2, + MODE_WRITE = 0x4, + MODE_APPEND = 0x8, +}; + +long smh_open(const char *fname, enum smh_open_mode mode); +long smh_read(long fd, void *memp, size_t len); +long smh_write(long fd, const void *memp, size_t len, size_t *written); +long smh_close(long fd); +long smh_flen(long fd); +long smh_seek(long fd, long pos); + +/* probe once, a boot without a debugger attached must not trap */ +bool smh_probe(void); + +#endif diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..93e2844 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2013 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __STDIO_H +#define __STDIO_H + +#include +#include + +/* fake FILE struct */ +typedef struct FILE { +} FILE; + +#define stdin ((FILE *)1) +#define stdout ((FILE *)2) +#define stderr ((FILE *)3) + +int fputc(int c, FILE *fp); +#define putc(c, fp) fputc(c, fp) +int putchar(int c); + +int fputs(const char *s, FILE *fp); +int puts(const char *str); + +int getc(FILE *fp); +int getchar(void); + +size_t fwrite(const void *buf, size_t size, size_t count, FILE *stream); +int sscanf(const char *str, const char *format, ...); + +#endif + diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..da2f229 --- /dev/null +++ b/include/string.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __LIB_STRING_H +#define __LIB_STRING_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *memchr (void const *, int, size_t) __PURE; +int memcmp (void const *, const void *, size_t) __PURE; +void *memcpy (void *, void const *, size_t); +void *memmove(void *, void const *, size_t); +void *memset (void *, int, size_t); + +char *strchr(char const *, int) __PURE; +int strcmp(char const *, char const *) __PURE; +char *strcpy(char *, char const *); +size_t strlen(char const *) __PURE; +int strncmp(char const *, char const *, size_t) __PURE; +char *strrchr(char const *, int) __PURE; +char *strstr(char const *, char const *) __PURE; +char *strstrn(char const *s1, char const *s2, size_t l2) __PURE; +size_t strnlen(char const *s, size_t count) __PURE; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* non standard */ +void bcopy(void const *, void *, size_t); +void bzero(void *, size_t); +size_t strlcat(char *, char const *, size_t); +size_t strlcpy(char *, char const *, size_t); +void strrev(unsigned char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/types.h b/include/sys/types.h new file mode 100644 index 0000000..70f6de1 --- /dev/null +++ b/include/sys/types.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008-2009 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef __SYS_TYPES_H +#define __SYS_TYPES_H + +#include +#include +#include +#include + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +#ifndef _SIZE_T_DEFINED_ +typedef unsigned long size_t; +#endif +typedef long ssize_t; +typedef long long off_t; + +typedef int status_t; + +typedef uintptr_t addr_t; +typedef uintptr_t vaddr_t; +typedef uintptr_t paddr_t; + +typedef int kobj_id; + +typedef unsigned long time_t; +typedef unsigned long long bigtime_t; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef bool boolean; + +#ifndef TRUE +#define TRUE true +#endif +#ifndef FALSE +#define FALSE false +#endif + +#define INFINITE_TIME ULONG_MAX + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#define TIME_GTE(a, b) ((long)((a) - (b)) >= 0) +#define TIME_LTE(a, b) ((long)((a) - (b)) <= 0) +#define TIME_GT(a, b) ((long)((a) - (b)) > 0) +#define TIME_LT(a, b) ((long)((a) - (b)) < 0) + +enum handler_return { + INT_NO_RESCHEDULE = 0, + INT_RESCHEDULE, +}; + +#endif -- cgit v1.2.3