diff options
author | Zachary Yedidia <zyedidia@gmail.com> | 2022-05-19 17:14:28 -0700 |
---|---|---|
committer | Zachary Yedidia <zyedidia@gmail.com> | 2022-05-19 17:14:28 -0700 |
commit | a950066d8a800e78445d8b2b89e2cfa03bd808e1 (patch) | |
tree | 380c0194b14f4fd24a00c0dea102eac6a2eccc04 | |
parent | 0b82ab2c9732d69f141361c659c7773fd4e6a38a (diff) | |
parent | f746a5d6fc1b1ec0044d1bd86d1ed2020837e9ec (diff) |
Merge branch 'exo'
-rw-r--r-- | .clang-format | 2 | ||||
-rw-r--r-- | .editorconfig | 2 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | INSTALL.md | 8 | ||||
-rw-r--r-- | cstart.c | 39 | ||||
-rw-r--r-- | defs.mk | 12 | ||||
-rw-r--r-- | hello_os/Makefile | 32 | ||||
-rw-r--r-- | hello_os/bits.h (renamed from bits.h) | 0 | ||||
-rw-r--r-- | hello_os/dev.h (renamed from dev.h) | 0 | ||||
-rw-r--r-- | hello_os/gpio.c | 19 | ||||
-rw-r--r-- | hello_os/gpio.h (renamed from gpio.h) | 0 | ||||
-rw-r--r-- | hello_os/hello.c | 27 | ||||
-rw-r--r-- | hello_os/memmap.ld (renamed from memmap.ld) | 0 | ||||
-rw-r--r-- | hello_os/start.s | 34 | ||||
-rw-r--r-- | hello_os/uart.c | 105 | ||||
-rw-r--r-- | hello_os/uart.h (renamed from uart.h) | 2 | ||||
-rw-r--r-- | i2c.c | 155 | ||||
-rw-r--r-- | i2c.h | 7 | ||||
-rw-r--r-- | interrupts-asm.s | 67 | ||||
-rw-r--r-- | kern.c | 13 | ||||
-rw-r--r-- | kern/Makefile | 64 | ||||
-rw-r--r-- | kern/asm.h (renamed from asm.h) | 7 | ||||
-rw-r--r-- | kern/bits.h | 78 | ||||
-rw-r--r-- | kern/boot.c | 89 | ||||
-rw-r--r-- | kern/dev.h | 5 | ||||
-rw-r--r-- | kern/gpio.c (renamed from gpio.c) | 16 | ||||
-rw-r--r-- | kern/gpio.h | 77 | ||||
-rw-r--r-- | kern/interrupts-asm.s | 81 | ||||
-rw-r--r-- | kern/interrupts.c (renamed from interrupts.c) | 64 | ||||
-rw-r--r-- | kern/interrupts.h (renamed from interrupts.h) | 4 | ||||
-rw-r--r-- | kern/kern.c | 81 | ||||
-rw-r--r-- | kern/kern.h | 29 | ||||
-rw-r--r-- | kern/kern.mk | 10 | ||||
-rw-r--r-- | kern/kmalloc.c | 239 | ||||
-rw-r--r-- | kern/kmalloc.h | 18 | ||||
-rw-r--r-- | kern/ksan.c | 228 | ||||
-rw-r--r-- | kern/ksan.h | 6 | ||||
-rw-r--r-- | kern/lib.h | 5 | ||||
-rw-r--r-- | kern/memmap.ld | 55 | ||||
-rw-r--r-- | kern/proc.c | 70 | ||||
-rw-r--r-- | kern/proc.h | 51 | ||||
-rw-r--r-- | kern/start.s | 29 | ||||
-rw-r--r-- | kern/sys.h (renamed from sys.h) | 48 | ||||
-rw-r--r-- | kern/syscall.c | 61 | ||||
-rw-r--r-- | kern/syscall_list.h | 14 | ||||
-rw-r--r-- | kern/timer.c (renamed from timer.c) | 3 | ||||
-rw-r--r-- | kern/timer.h (renamed from timer.h) | 1 | ||||
-rw-r--r-- | kern/u-syscall.h | 61 | ||||
-rw-r--r-- | kern/uart.c (renamed from uart.c) | 6 | ||||
-rw-r--r-- | kern/uart.h | 18 | ||||
-rw-r--r-- | kern/vm.c | 74 | ||||
-rw-r--r-- | kern/vm.h (renamed from vm.h) | 50 | ||||
-rw-r--r-- | kmalloc.c | 238 | ||||
-rw-r--r-- | kmalloc.h | 7 | ||||
-rw-r--r-- | ksan.c | 132 | ||||
-rw-r--r-- | ksan.h | 7 | ||||
-rw-r--r-- | libc/libc.c | 34 | ||||
-rw-r--r-- | libc/rand.c | 18 | ||||
-rw-r--r-- | libc/rand.h | 3 | ||||
-rw-r--r-- | libc/tinyprintf.c | 196 | ||||
-rw-r--r-- | libc/tinyprintf.h | 16 | ||||
-rw-r--r-- | pid_os/Makefile | 32 | ||||
-rw-r--r-- | pid_os/bits.h | 78 | ||||
-rw-r--r-- | pid_os/dev.h | 5 | ||||
-rw-r--r-- | pid_os/gpio.c | 19 | ||||
-rw-r--r-- | pid_os/gpio.h | 75 | ||||
-rw-r--r-- | pid_os/memmap.ld | 32 | ||||
-rw-r--r-- | pid_os/pidos.c | 18 | ||||
-rw-r--r-- | pid_os/start.s | 34 | ||||
-rw-r--r-- | pid_os/uart.c | 105 | ||||
-rw-r--r-- | pid_os/uart.h | 18 | ||||
-rw-r--r-- | pios.h | 38 | ||||
-rw-r--r-- | pios.mk | 8 | ||||
-rw-r--r-- | plugin/memtrace/Makefile | 10 | ||||
-rw-r--r-- | plugin/memtrace/memtrace.c | 87 | ||||
-rw-r--r-- | prog/ads1115/Makefile | 32 | ||||
-rw-r--r-- | prog/ads1115/ads1115.c | 35 | ||||
-rw-r--r-- | prog/ads1115/ads1115.h | 13 | ||||
-rw-r--r-- | prog/ads1115/main.c | 16 | ||||
-rw-r--r-- | prog/analyzer/Makefile | 28 | ||||
-rw-r--r-- | prog/analyzer/analyzer.c | 92 | ||||
-rw-r--r-- | prog/basic/Makefile | 14 | ||||
-rw-r--r-- | prog/basic/basic.ld | 20 | ||||
-rw-r--r-- | prog/basic/basic.s | 6 | ||||
-rw-r--r-- | prog/gpio_int/Makefile | 32 | ||||
-rw-r--r-- | prog/gpio_int/gpio_int.c | 31 | ||||
-rw-r--r-- | prog/hello/Makefile | 32 | ||||
-rw-r--r-- | prog/hello/hello.c | 6 | ||||
-rw-r--r-- | prog/irq/Makefile | 32 | ||||
-rw-r--r-- | prog/irq/irq.c | 34 | ||||
-rw-r--r-- | prog/mmu/Makefile | 36 | ||||
-rw-r--r-- | prog/mmu/mmu.c | 38 | ||||
-rw-r--r-- | prog/mmu_realtime/Makefile | 37 | ||||
-rw-r--r-- | prog/mmu_realtime/irq.s | 17 | ||||
-rw-r--r-- | prog/mmu_realtime/mmu_realtime.c | 72 | ||||
-rw-r--r-- | prog/san/Makefile | 36 | ||||
-rw-r--r-- | prog/san/san.c | 70 | ||||
-rw-r--r-- | prog/threads/Makefile | 37 | ||||
-rw-r--r-- | prog/threads/irq_asm.s | 18 | ||||
-rw-r--r-- | prog/threads/threads.c | 76 | ||||
-rw-r--r-- | prog/ws2812b/Makefile | 25 | ||||
-rw-r--r-- | prog/ws2812b/lights.c | 47 | ||||
-rw-r--r-- | prog/ws2812b/lights.h | 49 | ||||
-rw-r--r-- | start.s | 19 | ||||
-rw-r--r-- | todo.txt | 4 | ||||
-rwxr-xr-x | tools/exify/exify.sh | 7 | ||||
-rw-r--r-- | vm.c | 46 |
107 files changed, 2451 insertions, 1984 deletions
diff --git a/.clang-format b/.clang-format index f6e12ca..863c901 100644 --- a/.clang-format +++ b/.clang-format @@ -4,4 +4,6 @@ IndentWidth: 4 SpaceAfterCStyleCast: true AlignConsecutiveMacros: true AlignConsecutiveBitFields: true +IndentCaseLabels: false +PointerAlignment: Right --- diff --git a/.editorconfig b/.editorconfig index 6110e72..00ed235 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,7 +3,7 @@ charset = utf-8 end_of_line = lf insert_final_newline = true -[*.[ch]] +[*.[chs]] indent_style = space indent_size = 4 trim_trailing_whitespace = true @@ -6,9 +6,11 @@ *.so *.vcd .*.sw* +kern/p-*.c /boot/firmware trace.txt tools/piprog/piprog tools/vcd/vcd tools/rduart/rduart tags +.deps diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..398576d --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,8 @@ +Installing qemu: + +``` +mkdir build +cd build +../configure --enable-plugins --target-list=arm-softmmu +make +``` diff --git a/cstart.c b/cstart.c deleted file mode 100644 index 99a65e5..0000000 --- a/cstart.c +++ /dev/null @@ -1,39 +0,0 @@ -#include <stdint.h> - -#include "libc/tinyprintf.h" -#include "pios.h" -#include "uart.h" - -void reboot() { - printf("DONE!!!\n"); - uart_tx_flush(); - - volatile uint32_t* PM_RSTC = (uint32_t*) 0x2010001c; - volatile uint32_t* PM_WDOG = (uint32_t*) 0x20100024; - - const int PM_PASSWORD = 0x5a000000; - const int PM_RSTC_WRCFG_FULL_RESET = 0x00000020; - - *PM_WDOG = PM_PASSWORD | 1; - *PM_RSTC = PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; - while (1) - ; -} - -void cstart() { - extern int __bss_start__, __bss_end__; - - int* bss = &__bss_start__; - int* bss_end = &__bss_end__; - - while (bss < bss_end) { - *bss++ = 0; - } - - timer_init(); - uart_init(115200); - init_printf(NULL, uart_putc); - - kernel_start(); - reboot(); -} @@ -8,9 +8,13 @@ OBJCOPY = $(PREFIX)-objcopy OBJDUMP = $(PREFIX)-objdump QEMU = qemu-system-arm +# Custom qemu with dev barrier checking +# QEMU = /home/zyedidia/programming/qemu-dev/build/qemu-system-arm BOARD = raspi1ap GDB = gdb-multiarch +O ?= s + LIBGCC = $(shell $(CC) --print-file-name=libgcc.a) CPU = arm1176jzf-s @@ -18,7 +22,7 @@ ARCH = armv6zk PIOS ?= $(shell git rev-parse --show-toplevel) -CFLAGS = -O$(O) -g -Wall -nostdlib -nostartfiles -ffreestanding -Wa,-mcpu=$(CPU) -Wa,-march=$(ARCH) +CFLAGS = -O$(O) -g -Wall -Werror -nostdlib -nostartfiles -ffreestanding -Wa,-mcpu=$(CPU) -Wa,-march=$(ARCH) ASFLAGS = -mcpu=$(CPU) -march=$(ARCH) LDFLAGS = -T $(MEMMAP) LDLIBS = $(LIBGCC) @@ -29,13 +33,13 @@ else ASAN_FLAGS = -DSANITIZE=0 endif -$(PIOS_OBJ_NOSAN): ASAN_FLAGS := -DSANITIZE=$(SANITIZE) +$(KERN_OBJ_NOSAN): ASAN_FLAGS := -DSANITIZE=$(SANITIZE) -%.o: %.c +%.o: %.c $(BUILDSTAMP) $(CC) $(CFLAGS) $(ASAN_FLAGS) $< -c -o $@ %.o: %.s - $(CPP) $< | $(AS) $(ASFLAGS) -c -o $@ + $(CPP) $(CPPFLAGS) $< | $(AS) $(ASFLAGS) -c -o $@ %.bin: %.elf $(OBJCOPY) $< -O binary $@ diff --git a/hello_os/Makefile b/hello_os/Makefile new file mode 100644 index 0000000..8a2cceb --- /dev/null +++ b/hello_os/Makefile @@ -0,0 +1,32 @@ +include ../defs.mk + +CFLAGS += -MMD + +MEMMAP = memmap.ld +INCLUDE = -I$(KERN) -I$(PIOS) +CFLAGS += $(INCLUDE) +ASFLAGS += $(INCLUDE) +CPPFLAGS += $(INCLUDE) +DEP = $(KERN_OBJ:.o=.d) + +OBJ = hello.o start.o uart.o gpio.o ../libc/tinyprintf.o + +all: hello.bin + +hello.elf: $(OBJ) + $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +$(PIOS)/kern/p-hello.o: hello.bin + $(LD) -r -b binary -o $@ $< + +exostall: $(PIOS)/kern/p-hello.o + +clean: + rm -f *.d *.list *.o *.elf *.bin + +-include $(DEP) + +format: + clang-format -i $(PIOS_CSRC) $(PIOS_HSRC) + +.PHONY: format all install diff --git a/hello_os/gpio.c b/hello_os/gpio.c new file mode 100644 index 0000000..1777031 --- /dev/null +++ b/hello_os/gpio.c @@ -0,0 +1,19 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "gpio.h" + +static volatile uint32_t* gpio_fsel = (uint32_t*) (GPIO_BASE); + +void gpio_set_func(unsigned pin, gpio_func_t fn) { + if (pin >= 32) + return; + unsigned off = (pin % 10) * 3; + unsigned idx = pin / 10; + + uint32_t v = gpio_fsel[idx]; + v &= ~(0b111 << off); + v |= fn << off; + gpio_fsel[idx] = v; +} diff --git a/hello_os/hello.c b/hello_os/hello.c new file mode 100644 index 0000000..74d0079 --- /dev/null +++ b/hello_os/hello.c @@ -0,0 +1,27 @@ +#include "uart.h" + +// extern uint32_t syscall(uint32_t syscall, uint32_t arg0, uint32_t arg1, uint32_t arg2); + +unsigned main() { + // unsigned gpio_page = 0x20200000; + // syscall(SYSCALL_MMU_MAP, gpio_page, gpio_page, ARG_PAGE_4KB); + // unsigned uart_page = 0x20215004 & (~(4096 - 1)); + // syscall(SYSCALL_MMU_MAP, uart_page, uart_page, ARG_PAGE_4KB); + + init_printf(NULL, uart_putc); + printf("Hello, world!\n"); + + unsigned cpsr = 0; + asm volatile("mrs %0, cpsr" : "=r"(cpsr)); + printf("CPSR appears to be %x\n", cpsr); + + unsigned sp = 0; + asm volatile("mov %0, sp" : "=r"(sp)); + printf("My stack appears to be at %x\n", sp); + + volatile unsigned *ker_val = (void*)0x80000005; + printf("Trying to access a kernel byte at 0x%x...\n", ker_val); + printf("Value: %x\n", *ker_val); + + return 24; +} diff --git a/memmap.ld b/hello_os/memmap.ld index f24fd56..f24fd56 100644 --- a/memmap.ld +++ b/hello_os/memmap.ld diff --git a/hello_os/start.s b/hello_os/start.s new file mode 100644 index 0000000..fb86cff --- /dev/null +++ b/hello_os/start.s @@ -0,0 +1,34 @@ +#include "../kern/syscall_list.h" + +#define STACK_ADDR 0x8000000 + +.section ".boot" + +.globl _start +_start: + mov r0, #SYSCALL_ALLOC_PAGE + mov r1, #SYSCALL_ARG_ANY_PAGE + mov r2, #SIZE_1MB + swi 0 // result in r0 + + mov r1, #STACK_ADDR // virtual page + sub r1, r1, #SIZE_1MB // start of page for stack + mov r2, r0 // physical page + mov r3, #0 // flags + mov r4, #SIZE_1MB // size + mov r0, #SYSCALL_VM_MAP + swi 0 + + mov sp, #STACK_ADDR // Now we have a stack ! + sub sp, sp, #4 + + bl main + + mov r1, r0 + mov r0, #SYSCALL_EXIT + swi 0 + +.globl syscall +syscall: + swi 0 + bx lr diff --git a/hello_os/uart.c b/hello_os/uart.c new file mode 100644 index 0000000..f69a791 --- /dev/null +++ b/hello_os/uart.c @@ -0,0 +1,105 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "dev.h" +#include "gpio.h" +#include "uart.h" + +typedef struct { + uint32_t io; + uint32_t ier; + uint32_t iir; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +} aux_periphs_t; + +#define ENABLE_UART 1 +#define RX_ENABLE (1 << 0) +#define TX_ENABLE (1 << 1) +#define CLEAR_TX_FIFO (1 << 1) +#define CLEAR_RX_FIFO (1 << 2) +#define CLEAR_FIFOS (CLEAR_TX_FIFO | CLEAR_RX_FIFO) +#define IIR_RESET ((0b11 << 6) | 1) + +// TODO: should eventually ask the kernel for access instead of using its pages +// (eventually these will be write protected) +#define pa2ka(pa) ((pa | (1 << 31))) +#define ka2pa(ka) ((ka & ~(1 << 31))) +static volatile uint32_t* const aux_enables = (uint32_t*) pa2ka(0x20215004); +static volatile aux_periphs_t* const uart = (aux_periphs_t*) pa2ka(0x20215040); + +void uart_init(unsigned baud) { + gpio_set_func(GPIO_TX, GPIO_FUNC_ALT5); + gpio_set_func(GPIO_RX, GPIO_FUNC_ALT5); + + dev_barrier(); + + *aux_enables = *aux_enables | ENABLE_UART; + + dev_barrier(); + + uart->cntl = 0; + uart->ier = 0; + uart->lcr = 0b11; + uart->mcr = 0; + uart->iir = IIR_RESET | CLEAR_FIFOS; + uart->baud = (250 * 1000 * 1000) / (baud * 8) - 1; + uart->cntl = RX_ENABLE | TX_ENABLE; + + dev_barrier(); +} + +bool uart_rx_empty() { + return bit_get(uart->stat, 0) == 0; +} + +unsigned uart_rx_sz() { + return bits_get(uart->stat, 16, 19); +} + +bool uart_can_tx() { + return bit_get(uart->stat, 1) != 0; +} + +uint8_t uart_rx() { + dev_barrier(); + while (uart_rx_empty()) + ; + uint8_t c = uart->io & 0xff; + dev_barrier(); + return c; +} + +void uart_tx(uint8_t c) { + dev_barrier(); + while (!uart_can_tx()) + ; + uart->io = c & 0xff; + dev_barrier(); +} + +void uart_putc(void* p, char c) { + (void) p; + uart_tx(c); +} + +bool uart_tx_empty() { + dev_barrier(); + + // broadcom p 18: "This bit (9) is set if the transmitter is idle and the + // transmit FIFO is empty." + // transmitter done: idle and empty + return bit_get(uart->stat, 9) == 1; +} + +void uart_tx_flush() { + while (!uart_tx_empty()) + ; +} @@ -3,7 +3,7 @@ #include <stdbool.h> #include <stdint.h> -#include "libc/tinyprintf.h" +#include "../libc/tinyprintf.h" void uart_init(unsigned baud); bool uart_rx_empty(); @@ -1,155 +0,0 @@ -#include <stdint.h> - -#include "dev.h" -#include "gpio.h" -#include "pios.h" - -typedef struct { - unsigned read : 1; // read transfer (0: write packet, 1: read packet) - unsigned _unused0 : 3; - unsigned clear : 2; // fifo clear (0b00: no action, 0bx1 or 0b1x: clear - // fifo, reads as 0) - unsigned _unused1 : 1; - unsigned st : 1; // start transfer - unsigned intd : 1; // interrupt on done - unsigned intt : 1; // interrupt on tx - unsigned intr : 1; // interrupt on rx - unsigned _unused2 : 4; - unsigned i2cen : 1; // i2c enable - unsigned _unused3 : 16; -} ctrl_reg_t; -_Static_assert(sizeof(ctrl_reg_t) == 4, "invalid size for ctrl_reg_t"); - -static ctrl_reg_t ctrl_clear(ctrl_reg_t c) { - c._unused0 = 0; - c._unused1 = 0; - c._unused2 = 0; - c._unused3 = 0; - return c; -} - -static ctrl_reg_t ctrl_read(volatile ctrl_reg_t* c) { - return ctrl_clear(*c); -} - -typedef struct { - unsigned ta : 1; // transfer active - unsigned done : 1; // transfer done - unsigned txw : 1; // fifo needs writing - unsigned rxr : 1; // fifo needs reading - unsigned txd : 1; // fifo can accept data - unsigned rxd : 1; // fifo contains data - unsigned txe : 1; // fifo empty - unsigned rxf : 1; // fifo full - unsigned err : 1; // ack error - unsigned clktk : 1; // clock stretch timeout - unsigned _unused0 : 22; -} stat_reg_t; -_Static_assert(sizeof(stat_reg_t) == 4, "invalid size for stat_reg_t"); - -static stat_reg_t stat_clear(stat_reg_t s) { - s._unused0 = 0; - return s; -} - -static stat_reg_t stat_read(volatile stat_reg_t* s) { - return stat_clear(*s); -} - -typedef struct { - ctrl_reg_t ctrl; - stat_reg_t status; - - uint32_t data_len; - uint32_t dev_addr; - uint32_t data_fifo; - uint32_t clock_div; - uint32_t clock_delay; - uint32_t clock_stretch_timeout; -} i2c_regs_t; - -static volatile i2c_regs_t* const i2c = (i2c_regs_t*) 0x20804000; // BSC1 - -static void reset_status() { - stat_reg_t s = stat_read(&i2c->status); - // all are cleared by writing 1 - s.done = 1; - s.err = 1; - s.clktk = 1; - i2c->status = s; -} - -void i2c_init() { - dev_barrier(); - gpio_set_func(GPIO_SDA, GPIO_FUNC_ALT0); - gpio_set_func(GPIO_SCL, GPIO_FUNC_ALT0); - dev_barrier(); - ctrl_reg_t ctrl; - memset(&ctrl, 0, sizeof(ctrl_reg_t)); - ctrl.i2cen = 1; - i2c->ctrl = ctrl; - reset_status(); - dev_barrier(); -} - -#define wait_for(_cond) \ - do { \ - while (!(_cond)) { \ - if (i2c->status.err) \ - panic("i2c slave ack error\n"); \ - if (i2c->status.clktk) \ - panic("i2c slave held line too long\n"); \ - } \ - } while (0) - -static void transfer_start(uint8_t addr, uint16_t nbytes, int read) { - // wait for any previous transfer to complete - wait_for(i2c->status.ta == 0); - reset_status(); - - i2c->dev_addr = addr; - i2c->data_len = nbytes; - - ctrl_reg_t c = ctrl_read(&i2c->ctrl); - c.clear = 0b11; - c.st = 1; - c.read = read; - i2c->ctrl = c; - - // wait until transfer begins - wait_for(i2c->status.ta == 1); -} - -static void transfer_end() { - wait_for(i2c->status.done == 1); -} - -int i2c_write(uint8_t addr, uint8_t* data, uint16_t nbytes) { - dev_barrier(); - transfer_start(addr, nbytes, 0); - - for (unsigned i = 0; i < nbytes; i++) { - // wait for there to be more room - wait_for(i2c->status.txd == 1); - i2c->data_fifo = data[i]; - } - - transfer_end(); - dev_barrier(); - return 1; -} - -int i2c_read(uint8_t addr, uint8_t* data, uint16_t nbytes) { - dev_barrier(); - transfer_start(addr, nbytes, 1); - - for (unsigned i = 0; i < nbytes; i++) { - // wait for at least one byte to be available - wait_for(i2c->status.rxd == 1); - data[i] = i2c->data_fifo & 0xff; - } - - transfer_end(); - dev_barrier(); - return 1; -} @@ -1,7 +0,0 @@ -#pragma once - -#include <stdint.h> - -void i2c_init(); -int i2c_write(uint8_t addr, uint8_t* data, uint16_t nbytes); -int i2c_read(uint8_t addr, uint8_t* data, uint16_t nbytes); diff --git a/interrupts-asm.s b/interrupts-asm.s deleted file mode 100644 index c7f8963..0000000 --- a/interrupts-asm.s +++ /dev/null @@ -1,67 +0,0 @@ -#include "asm.h" - -.globl _interrupt_table -.globl _interrupt_table_end -_interrupt_table: - ldr pc, _reset_h - ldr pc, _undef_insn_h - ldr pc, _software_irq_h - ldr pc, _prefetch_abort_h - ldr pc, _data_abort_h - ldr pc, _reset_h - ldr pc, _irq_h - ldr pc, _fiq_h - -_reset_h: .word asm_reset -_undef_insn_h: .word asm_undef_insn -_software_irq_h: .word asm_software_irq -_prefetch_abort_h: .word asm_prefetch_abort -_data_abort_h: .word asm_data_abort -_irq_h: .word asm_irq -_fiq_h: .word asm_fiq -_interrupt_table_end: - -asm_reset: - mov sp, #INT_STACK_ADDR - bl reboot -asm_undef_insn: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_undef_insn -asm_software_irq: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_software_irq -asm_prefetch_abort: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_prefetch_abort -asm_data_abort: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_data_abort -asm_irq: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_irq -asm_fiq: - mov sp, #INT_STACK_ADDR - ldr pc, _vec_fiq - -.globl _vector_table -_vector_table: -_vec_undef_insn: .word vec_undef_insn -_vec_software_irq: .word vec_software_irq -_vec_prefetch_abort: .word vec_prefetch_abort -_vec_data_abort: .word vec_data_abort -_vec_irq: .word vec_irq -_vec_fiq: .word vec_fiq - -.globl enable_interrupts -enable_interrupts: - mrs r0, cpsr - bic r0, r0, #(1 << 7) - msr cpsr_c, r0 - bx lr - -.globl disable_interrupts -disable_interrupts: - mrs r0, cpsr - orr r0, r0, #(1 << 7) - msr cpsr_c, r0 - bx lr @@ -1,13 +0,0 @@ -#include "pios.h" - -extern int main(); - -void kernel_start() { -#if (SANITIZE == 1) - asan_enable(); -#endif - cache_enable(); - - main(); - return; -} diff --git a/kern/Makefile b/kern/Makefile new file mode 100644 index 0000000..139efc4 --- /dev/null +++ b/kern/Makefile @@ -0,0 +1,64 @@ +all: kern.bin + +O ?= s + +# these rules ensure dependencies are created +DEPCFLAGS = -MD -MF $(DEPSDIR)/$(notdir $*).d -MP +DEPSDIR := .deps +BUILDSTAMP := $(DEPSDIR)/rebuildstamp +DEPFILES := $(wildcard $(DEPSDIR)/*.d) +ifneq ($(DEPFILES),) +include $(DEPFILES) +endif + +include kern.mk +include ../defs.mk + +CFLAGS += $(DEPCFLAGS) + +ifneq ($(RANDOMIZE),) +CFLAGS += -DRANDOMIZE_KMALLOC +endif + +INCLUDE = -I$(KERN) -I$(PIOS) +CFLAGS += $(INCLUDE) +ASFLAGS += $(INCLUDE) +CPPFLAGS += $(INCLUDE) +DEP = $(KERN_OBJ:.o=.d) + +# when the C compiler or optimization flags change, rebuild all objects +ifneq ($(strip $(DEP_CC)),$(strip $(CC) $(CFLAGS) $(ASAN_FLAGS) $(O))) +DEP_CC := $(shell mkdir -p $(DEPSDIR); echo >$(BUILDSTAMP); echo "DEP_CC:=$(CC) $(CFLAGS) $(ASAN_FLAGS) $(O)" >$(DEPSDIR)/_cc.d) +endif + +kern.elf: $(MEMMAP) $(KERN_OBJ) + $(LD) $(LDFLAGS) $(filter-out $<,$^) $(LDLIBS) -o $@ + +install: kern.bin + pi-install $< + +clean: + rm -rf *.d *.list *.o *.elf *.bin .deps + +-include $(DEP) + +qemu: kern.elf + $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot + +qemu-gdb: kern.elf + $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & + $(GDB) -ex "file kern.elf" -ex "target remote localhost:1234" + +format: + clang-format -i $(KERN_CSRC) $(KERN_HSRC) + +p-basic.o: + make -C $(PIOS)/prog/basic exostall + +p-hello.o: + make -C $(PIOS)/hello_os exostall + +p-pidos.o: + make -C $(PIOS)/pid_os exostall + +.PHONY: format all install p-basic.o p-hello.o p-pidos.o @@ -1,12 +1,5 @@ #pragma once -#define prefetch_flush(reg) \ - mov reg, #0; \ - mcr p15, 0, reg, c7, c5, 4 - -#define STACK_ADDR 0x8000000 -#define INT_STACK_ADDR 0x9000000 - // from A2-2 #define USER_MODE 0b10000 #define FIQ_MODE 0b10001 diff --git a/kern/bits.h b/kern/bits.h new file mode 100644 index 0000000..f0f16a2 --- /dev/null +++ b/kern/bits.h @@ -0,0 +1,78 @@ +#pragma once + +#include <stdint.h> + +static inline uint32_t bit_clr(uint32_t x, unsigned bit) { + return x & ~(1 << bit); +} + +static inline uint32_t bit_set(uint32_t x, unsigned bit) { + return x | (1 << bit); +} + +static inline uint32_t bit_assign(uint32_t x, unsigned bit, unsigned val) { + x = bit_clr(x, bit); + return x | (val << bit); +} + +#define bit_isset bit_is_on +#define bit_get bit_is_on + +static inline unsigned bit_is_on(uint32_t x, unsigned bit) { + return (x >> bit) & 1; +} +static inline unsigned bit_is_off(uint32_t x, unsigned bit) { + return bit_is_on(x, bit) == 0; +} + +static inline uint32_t bits_mask(unsigned nbits) { + if (nbits == 32) + return ~0; + return (1 << nbits) - 1; +} + +static inline uint32_t bits_get(uint32_t x, unsigned lb, unsigned ub) { + return (x >> lb) & bits_mask(ub - lb + 1); +} + +static inline uint32_t bits_clr(uint32_t x, unsigned lb, unsigned ub) { + uint32_t mask = bits_mask(ub - lb + 1); + return x & ~(mask << lb); +} + +static inline uint32_t bits_set(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t v) { + return bits_clr(x, lb, ub) | (v << lb); +} + +static inline unsigned bits_eq(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t val) { + return bits_get(x, lb, ub) == val; +} + +static inline unsigned bit_count(uint32_t x) { + unsigned cnt = 0; + for (unsigned i = 0; i < 32; i++) + if (bit_is_on(x, i)) + cnt++; + return cnt; +} + +static inline uint32_t bits_union(uint32_t x, uint32_t y) { + return x | y; +} + +static inline uint32_t bits_intersect(uint32_t x, uint32_t y) { + return x & y; +} +static inline uint32_t bits_not(uint32_t x) { + return ~x; +} + +static inline uint32_t bits_diff(uint32_t A, uint32_t B) { + return bits_intersect(A, bits_not(B)); +} diff --git a/kern/boot.c b/kern/boot.c new file mode 100644 index 0000000..08b6c52 --- /dev/null +++ b/kern/boot.c @@ -0,0 +1,89 @@ +#include <stdint.h> + +#include "asm.h" +#include "kern.h" +#include "sys.h" +#include "vm.h" +#include "timer.h" + +static pte_1mb_t __attribute__((aligned(1 << 14))) kernel_pagetable[4096]; + +// all functions in this file go in .text.boot so they exist at low addresses +// (these functions run before the MMU is enabled). +static void __attribute__((section(".text.boot"))) +vm_kernel_map(uintptr_t va, uintptr_t pa); +static void __attribute__((section(".text.boot"))) vm_kernel_enable(); +static void __attribute__((section(".text.boot"))) +dmap_kernel_section(uintptr_t pa); +static void __attribute__((section(".text.boot"))) dmap_kernel_sections(); +void __attribute__((section(".text.boot"))) cstart(); +extern void __attribute__((section(".text.boot"))) _hlt(); + +// map va to pa in the kernel pagetable +static void vm_kernel_map(uintptr_t va, uintptr_t pa) { + // since we are running before the mmu is enabled, physical addresses are + // the actual addresses so we need to convert kernel_pagetable from a + // kernel address before using it + pte_1mb_t *pgtbl = (pte_1mb_t *) ka2pa((uintptr_t) kernel_pagetable); + + unsigned pte_idx = va >> 20; + pte_1mb_t *pte = &pgtbl[pte_idx]; + + if (pte->tag != 0b00) { + _hlt(); + } + + pte->tag = 0b10; + pte->sec_base_addr = pa >> 20; + pte->ap = AP_KER_RW; +} + +// double map pa as pa -> pa and pa2ka(pa) -> pa +static void dmap_kernel_section(uintptr_t pa) { + vm_kernel_map(pa, pa); + vm_kernel_map(pa2ka(pa), pa); +} + +// double map all kernel regions +static void dmap_kernel_sections() { + // map kernel + for (uintptr_t pa = 0; pa < MEMSIZE_PHYSICAL; pa += SIZE_1MB) { + dmap_kernel_section(pa); + } + // map uart, gpio, watchdog timer + dmap_kernel_section(0x20000000); + dmap_kernel_section(0x20100000); + dmap_kernel_section(0x20200000); + sys_clean_and_invalidate_cache(); + sys_invalidate_tlb(); +} + +// enable the kernel pagetable +static void vm_kernel_enable() { + sys_invalidate_cache(); + sys_invalidate_tlb(); + dsb(); + sys_set_domain(DOM_CLIENT); + sys_set_tlb_base(ka2pa((uintptr_t) kernel_pagetable)); + sys_set_cache_control(SYS_MMU_ENABLE | SYS_DCACHE_ENABLE | + SYS_ICACHE_ENABLE | SYS_BRANCH_PREDICTION_ENABLE | + SYS_WRITE_BUFFER_ENABLE | SYS_MMU_XP); +} + +void cstart() { + timer_init(); + extern int _kbss_start, _kbss_end; + int *bss = (int *) ka2pa((uintptr_t) &_kbss_start); + int *bss_end = (int *) ka2pa((uintptr_t) &_kbss_end); + while (bss < bss_end) { + *bss++ = 0; + } + + dmap_kernel_sections(); + vm_kernel_enable(); + + extern void stack_to_ka(); + stack_to_ka(); + kernel_start(); // shouldn't return + _hlt(); +} diff --git a/kern/dev.h b/kern/dev.h new file mode 100644 index 0000000..1f644f7 --- /dev/null +++ b/kern/dev.h @@ -0,0 +1,5 @@ +#pragma once + +static inline void dev_barrier() { + asm volatile("mcr p15, 0, r0, c7, c10, 4"); +} @@ -6,14 +6,14 @@ #include "interrupts.h" #include "timer.h" -static volatile uint32_t* gpio_fsel = (uint32_t*) (GPIO_BASE); -static volatile uint32_t* gpio_eds = (uint32_t*) (GPIO_BASE + 0x40); -static volatile uint32_t* gpio_ren = (uint32_t*) (GPIO_BASE + 0x4c); -static volatile uint32_t* gpio_fen = (uint32_t*) (GPIO_BASE + 0x58); -static volatile uint32_t* gpio_aren = (uint32_t*) (GPIO_BASE + 0x7c); -static volatile uint32_t* gpio_afen = (uint32_t*) (GPIO_BASE + 0x88); -static volatile uint32_t* gpio_pud = (uint32_t*) (GPIO_BASE + 0x94); -static volatile uint32_t* gpio_pudclk = (uint32_t*) (GPIO_BASE + 0x98); +static volatile uint32_t *gpio_fsel = (uint32_t *) (GPIO_BASE); +static volatile uint32_t *gpio_eds = (uint32_t *) (GPIO_BASE + 0x40); +static volatile uint32_t *gpio_ren = (uint32_t *) (GPIO_BASE + 0x4c); +static volatile uint32_t *gpio_fen = (uint32_t *) (GPIO_BASE + 0x58); +static volatile uint32_t *gpio_aren = (uint32_t *) (GPIO_BASE + 0x7c); +static volatile uint32_t *gpio_afen = (uint32_t *) (GPIO_BASE + 0x88); +static volatile uint32_t *gpio_pud = (uint32_t *) (GPIO_BASE + 0x94); +static volatile uint32_t *gpio_pudclk = (uint32_t *) (GPIO_BASE + 0x98); void gpio_set_func(unsigned pin, gpio_func_t fn) { if (pin >= 32) diff --git a/kern/gpio.h b/kern/gpio.h new file mode 100644 index 0000000..15161d2 --- /dev/null +++ b/kern/gpio.h @@ -0,0 +1,77 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "vm.h" + +enum { + GPIO_TX = 14, + GPIO_RX = 15, + GPIO_SDA = 2, + GPIO_SCL = 3, +}; + +typedef enum { + GPIO_FUNC_INPUT = 0, + GPIO_FUNC_OUTPUT = 1, + GPIO_FUNC_ALT0 = 4, + GPIO_FUNC_ALT1 = 5, + GPIO_FUNC_ALT2 = 6, + GPIO_FUNC_ALT3 = 7, + GPIO_FUNC_ALT4 = 3, + GPIO_FUNC_ALT5 = 2, +} gpio_func_t; + +#define GPIO_BASE pa2ka(0x20200000U) + +static volatile uint32_t *gpio_set = (uint32_t *) (GPIO_BASE + 0x1C); +static volatile uint32_t *gpio_clr = (uint32_t *) (GPIO_BASE + 0x28); +static volatile uint32_t *gpio_lev = (uint32_t *) (GPIO_BASE + 0x34); + +void gpio_set_func(unsigned pin, gpio_func_t fn); +void gpio_set_output(unsigned pin); +void gpio_set_on(unsigned pin); +void gpio_set_off(unsigned pin); +void gpio_set_input(unsigned pin); +void gpio_write(unsigned pin, bool v); +bool gpio_read(unsigned pin); + +static inline void gpio_set_on_fast(unsigned pin) { + gpio_set[0] = 1 << pin; +} + +static inline void gpio_set_off_fast(unsigned pin) { + gpio_clr[0] = 1 << pin; +} + +static inline void gpio_write_fast(unsigned pin, bool v) { + if (v) { + gpio_set_on_fast(pin); + } else { + gpio_set_off_fast(pin); + } +} + +static inline bool gpio_read_fast(unsigned pin) { + return (gpio_lev[0] >> pin) & 1; +} + +void gpio_set_pullup(unsigned pin); +void gpio_set_pulldown(unsigned pin); +void gpio_pud_off(unsigned pin); + +enum { + GPIO_INT0 = 49, + GPIO_INT1, + GPIO_INT2, + GPIO_INT3, +}; + +int is_gpio_int(unsigned gpio_int); +void gpio_int_rise(unsigned pin); +void gpio_int_fall(unsigned pin); +void gpio_int_rise_async(unsigned pin); +void gpio_int_fall_async(unsigned pin); +int gpio_event_detect(unsigned pin); +void gpio_event_clear(unsigned pin); diff --git a/kern/interrupts-asm.s b/kern/interrupts-asm.s new file mode 100644 index 0000000..c90a24c --- /dev/null +++ b/kern/interrupts-asm.s @@ -0,0 +1,81 @@ +#include "asm.h" + +.globl _interrupt_table +.globl _interrupt_table_end +.align 5 +_interrupt_table: + ldr pc, _reset_h + ldr pc, _undef_insn_h + ldr pc, _software_irq_h + ldr pc, _prefetch_abort_h + ldr pc, _data_abort_h + ldr pc, _reset_h + ldr pc, _irq_h + ldr pc, _fiq_h + +_reset_h: .word asm_reset +_undef_insn_h: .word asm_undef_insn +_software_irq_h: .word asm_software_irq +_prefetch_abort_h: .word asm_prefetch_abort +_data_abort_h: .word asm_data_abort +_irq_h: .word asm_irq +_fiq_h: .word asm_fiq +_interrupt_table_end: + +asm_reset: + ldr sp, =kstack + bl reboot +asm_undef_insn: + ldr sp, =kstack + ldr pc, _vec_undef_insn +asm_software_irq: + ldr sp, =kstack + // sub lr, lr, #4 + push {lr} + stmfd sp, {r0-r14}^ + sub sp, sp, #60 + mov r0, sp + bl syscall + ldm sp, {r0-r15}^ +asm_prefetch_abort: + ldr sp, =kstack + ldr pc, _vec_prefetch_abort +asm_data_abort: + ldr sp, =kstack + ldr pc, _vec_data_abort +asm_irq: + ldr sp, =kstack + sub lr, lr, #4 + push {lr} + stmfd sp, {r0-r14}^ + sub sp, sp, #60 + mov r0, sp + ldr r1, _vec_irq + blx r1 + ldm sp, {r0-r15}^ +asm_fiq: + ldr sp, =kstack + ldr pc, _vec_fiq + +.globl _vector_table +_vector_table: +_vec_undef_insn: .word vec_undef_insn +_vec_software_irq: .word vec_software_irq +_vec_prefetch_abort: .word vec_prefetch_abort +_vec_data_abort: .word vec_data_abort +_vec_irq: .word vec_irq +_vec_fiq: .word vec_fiq + +.globl enable_interrupts +enable_interrupts: + mrs r0, cpsr + bic r0, r0, #(1 << 7) + msr cpsr_c, r0 + bx lr + +.globl disable_interrupts +disable_interrupts: + mrs r0, cpsr + orr r0, r0, #(1 << 7) + msr cpsr_c, r0 + bx lr diff --git a/interrupts.c b/kern/interrupts.c index 8a2e46f..7322ef8 100644 --- a/interrupts.c +++ b/kern/interrupts.c @@ -1,5 +1,13 @@ +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +#include "bits.h" #include "dev.h" -#include "pios.h" +#include "interrupts.h" +#include "kern.h" +#include "sys.h" +#include "vm.h" typedef struct { uint32_t irq_basic_pending; @@ -11,7 +19,7 @@ typedef struct { uint32_t disable_basic_irqs; } irq_ctrl_t; -static volatile irq_ctrl_t* const irq_ctrl = (irq_ctrl_t*) 0x2000B200; +static volatile irq_ctrl_t *const irq_ctrl = (irq_ctrl_t *) pa2ka(0x2000b200); void irq_enable_basic(uint32_t irq) { irq_ctrl->enable_basic_irqs = bit_set(irq_ctrl->enable_basic_irqs, irq); @@ -39,26 +47,35 @@ bool irq_pending(uint32_t irq) { return bit_get(irq_ctrl->irq_pending[irq / 32], irq % 32); } -#define IRQ_VECTOR_START 0 -void irq_init_table() { +void irq_init() { + irq_ctrl->disable_irqs[0] = 0xffffffff; + irq_ctrl->disable_irqs[1] = 0xffffffff; + dev_barrier(); + + extern char _interrupt_table; + uintptr_t addr = (uintptr_t) &_interrupt_table; + sys_set_vec_base(addr); +} + +void irq_init_table(uintptr_t addr) { irq_ctrl->disable_irqs[0] = 0xffffffff; irq_ctrl->disable_irqs[1] = 0xffffffff; dev_barrier(); - extern unsigned _interrupt_table; - extern unsigned _interrupt_table_end; + extern char _interrupt_table; + extern char _interrupt_table_end; - volatile unsigned* dst = (unsigned*) IRQ_VECTOR_START; - unsigned* src = &_interrupt_table; - unsigned n = &_interrupt_table_end - src; - for (unsigned i = 0; i < n; i++) { - dst[i] = src[i]; - } + char *dst = (char *) addr; + char *src = (char *) &_interrupt_table; + size_t n = &_interrupt_table_end - src; + memcpy(dst, src, n); + + sys_set_vec_base(addr); } extern uintptr_t _vector_table; -static volatile uintptr_t* const vec_tbl = (uintptr_t*) &_vector_table; +static volatile uintptr_t *const vec_tbl = (uintptr_t *) &_vector_table; void register_irq_vec(irq_vec_t vec, uintptr_t fn) { vec_tbl[vec] = fn; @@ -73,13 +90,30 @@ void __attribute__((interrupt("SWI"))) vec_software_irq() { panic_unhandled("software_irq"); } void __attribute__((interrupt("ABORT"))) vec_prefetch_abort() { + printf("~~~~~~~~~~~~~~~~~~~~~~~ PANIC ~~~~~~~~~~~~~~~~~~~~~~~\n"); + printf("!!!!!!! IFaulted on 0x%x\n", get_ifar()); panic_unhandled("prefetch_abort"); } void __attribute__((interrupt("ABORT"))) vec_data_abort() { + unsigned lr; + asm volatile("mov %0, lr" : "=r"(lr)); + printf("~~~~~~~~~~~~~~~~~~~~~~~ PANIC ~~~~~~~~~~~~~~~~~~~~~~~\n"); + printf("!!!!!!! DFaulted on 0x%x\n", get_dfar()); + printf("!!!!!!! LR was: %x\n", lr); panic_unhandled("data_abort"); } -void __attribute__((interrupt("IRQ"))) vec_irq() { - panic_unhandled("irq"); +#include "proc.h" +#include "timer.h" +void vec_irq(regs_t *regs) { + dev_barrier(); + if (!timer_has_irq()) + return; + + proc_scheduler_irq(regs); + + dev_barrier(); + timer_clear_irq(); + dev_barrier(); } void __attribute__((interrupt("FIQ"))) vec_fiq() { panic_unhandled("fiq"); diff --git a/interrupts.h b/kern/interrupts.h index b21e57b..dcff5b7 100644 --- a/interrupts.h +++ b/kern/interrupts.h @@ -1,5 +1,6 @@ #pragma once +#include <stdbool.h> #include <stdint.h> #define BASIC_TIMER_IRQ 0 @@ -27,7 +28,8 @@ typedef enum { void register_irq_vec(irq_vec_t vec, uintptr_t fn); -void irq_init_table(); +void irq_init_table(uintptr_t addr); +void irq_init(); void enable_interrupts(); void disable_interrupts(); bool irq_basic_pending(uint32_t irq); diff --git a/kern/kern.c b/kern/kern.c new file mode 100644 index 0000000..255dc59 --- /dev/null +++ b/kern/kern.c @@ -0,0 +1,81 @@ +#include <stdint.h> + +#include "asm.h" +#include "gpio.h" +#include "interrupts.h" +#include "kern.h" +#include "kmalloc.h" +#include "ksan.h" +#include "proc.h" +#include "sys.h" +#include "timer.h" +#include "uart.h" +#include "vm.h" +#include "libc/rand.h" + +/* #define PIDOS */ +/* #define HELLOOS */ + +void reboot() { + printf("DONE!!!\n"); + uart_tx_flush(); + + dsb(); + + volatile uint32_t *PM_RSTC = (uint32_t *) pa2ka(0x2010001c); + volatile uint32_t *PM_WDOG = (uint32_t *) pa2ka(0x20100024); + + const int PM_PASSWORD = 0x5a000000; + const int PM_RSTC_WRCFG_FULL_RESET = 0x00000020; + + *PM_WDOG = PM_PASSWORD | 1; + *PM_RSTC = PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; + while (1) + ; +} + +void kernel_start() { +#if (SANITIZE == 1) + asan_enable(); +#endif + + sys_enable_cache(); + uart_init(115200); + init_printf(NULL, uart_putc); + + rand_seed(timer_cycles()); + + kmalloc_init(); + + irq_init(); + irq_enable(BASIC_TIMER_IRQ); + dsb(); + timer_irq_load(0x1000); + + printf("kernel booted\n"); + +#ifdef PIDOS + extern uint8_t _binary_pidos_bin_start; + extern uint8_t _binary_pidos_bin_end; + proc_t *p_pidos_1 = + proc_new(&_binary_pidos_bin_start, &_binary_pidos_bin_end); + proc_new(&_binary_pidos_bin_start, &_binary_pidos_bin_end); + enable_interrupts(); // TODO: Set this in the SPSR + proc_run(p_pidos_1); +#elif defined(HELLOOS) + extern uint8_t _binary_hello_bin_start; + extern uint8_t _binary_hello_bin_end; + proc_t *p_hello = + proc_new(&_binary_hello_bin_start, &_binary_hello_bin_end); + proc_run(p_hello); +#else + extern uint8_t _binary_basic_bin_start; + extern uint8_t _binary_basic_bin_end; + proc_t *p_basic = + proc_new(&_binary_basic_bin_start, &_binary_basic_bin_end); + proc_run(p_basic); +#endif + + reboot(); + return; +} diff --git a/kern/kern.h b/kern/kern.h new file mode 100644 index 0000000..5d0f821 --- /dev/null +++ b/kern/kern.h @@ -0,0 +1,29 @@ +#pragma once + +#include "libc/tinyprintf.h" + +void reboot(); +void kernel_start(); + +#define LOG_MEMSIZE_PHYSICAL 21 +#define MEMSIZE_PHYSICAL (1 << LOG_MEMSIZE_PHYSICAL) + +#define PAGESIZE 4096 + +typedef struct { + uint8_t page[PAGESIZE]; +} page_t; + +#define panic(format, args...) \ + do { \ + printf("PANIC: "); \ + printf(format, ##args); \ + reboot(); \ + } while (0) + +#define assert(x) \ + while (!(x)) { \ + printf("ASSERTION FAIL: "); \ + printf("%s\n", #x); \ + reboot(); \ + } diff --git a/kern/kern.mk b/kern/kern.mk new file mode 100644 index 0000000..e098b86 --- /dev/null +++ b/kern/kern.mk @@ -0,0 +1,10 @@ +KERN = $(PIOS)/kern + +MEMMAP = $(KERN)/memmap.ld + +KERN_CSRC = $(wildcard $(KERN)/*.c) $(wildcard $(PIOS)/libc/*.c) +KERN_HSRC = $(wildcard $(KERN)/*.h) $(wildcard $(PIOS)/libc/*.h) +KERN_SSRC = $(wildcard $(KERN)/*.s) + +KERN_OBJ_NOSAN = $(KERN)/ksan.o $(KERN)/boot.o $(KERN)/uart.o $(KERN)/start.o $(KERN)/gpio.o $(KERN)/kmalloc.o $(PIOS)/libc/tinyprintf.o +KERN_OBJ = $(KERN_CSRC:.c=.o) $(KERN_SSRC:.s=.o) $(wildcard p-*.o) diff --git a/kern/kmalloc.c b/kern/kmalloc.c new file mode 100644 index 0000000..76b61af --- /dev/null +++ b/kern/kmalloc.c @@ -0,0 +1,239 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "libc/rand.h" +#include "kern.h" +#include "kmalloc.h" +#include "ksan.h" +#include "lib.h" +#include "vm.h" + +// allocates pages of size 4096 +#define MIN_ORDER 12 +#define MAX_ORDER LOG_MEMSIZE_PHYSICAL + +typedef struct { + bool free; + unsigned order; +} phys_page_t; + +typedef struct free_page { + struct free_page *next; + struct free_page *prev; +} free_page_t; + +// free list for each type of order +static free_page_t *free_lists[MAX_ORDER + 1]; + +static void ll_free_insert(free_page_t *n, int order) { + n->next = free_lists[order]; + n->prev = NULL; + if (free_lists[order]) + free_lists[order]->prev = n; + free_lists[order] = n; +} + +static void ll_free_remove(free_page_t *n, int order) { + if (n->next) + n->next->prev = n->prev; + if (n->prev) + n->prev->next = n->next; + else + free_lists[order] = n->next; +} + +static phys_page_t pages[MEMSIZE_PHYSICAL / PAGESIZE]; + +// Checks if a page number is valid for a given order +static bool valid(uintptr_t pn, unsigned order) { + return pageaddr(pn) % (1 << order) == 0; +} + +// Returns the page number of the buddy of the page stored at pn. Returns -1 if +// the given pn is not valid +static uintptr_t get_buddy(uintptr_t pn) { + phys_page_t p = pages[pn]; + if (p.order < MIN_ORDER || p.order > MAX_ORDER || !valid(pn, p.order)) { + return -1; + } + + size_t pa = pageaddr(pn); + if (valid(pn, p.order + 1)) { + return pagenum(pa + (1 << p.order)); + } + return pagenum(pa - (1 << p.order)); +} + +static free_page_t *pn_to_free(uintptr_t pn) { + return (free_page_t *) pa2ka(pageaddr(pn)); +} + +extern char _kheap_start, _boot_start; + +// Initialize everything needed for kmalloc +void kmalloc_init() { + // Iterate through all heap memory, mark as free, and coalesce blocks + // together if possible + uintptr_t text_start = ka2pa((uintptr_t) &_boot_start); + uintptr_t heap_start = ka2pa((uintptr_t) &_kheap_start); + for (uintptr_t pa = 0; pa < MEMSIZE_PHYSICAL; pa += PAGESIZE) { + uintptr_t pn = pagenum(pa); + pages[pn].free = pa >= heap_start || pa < text_start; + pages[pn].order = MIN_ORDER; + + unsigned order = pages[pn].order; + while (valid(pn, order)) { + uintptr_t bpn = get_buddy(pn); // buddy pn + // We can coalesce backwards + if (bpn < pn && pages[bpn].free == pages[pn].free && + pages[bpn].order == pages[pn].order) { + // Merge blocks + pages[bpn].order++; + order++; + pages[pn].order = 0; + pn = bpn; + continue; + } + break; + } + } + + // Now we set up the free lists by looping over each block and adding it to + // the list + uintptr_t pn = 0; + while (pn < pagenum(MEMSIZE_PHYSICAL)) { + phys_page_t page = pages[pn]; + assert(valid(pn, page.order)); + if (page.free) { + ll_free_insert(pn_to_free(pn), page.order); + } + pn += pagenum(1 << page.order); + } +} + +// Allocate and returns a pointer to at least `sz` contiguous bytes of memory. +// Returns `NULL` if `sz == 0` or on failure. +static void *kmalloc_internal(size_t sz) { + if (sz == 0) { + return NULL; + } + + unsigned order = msb(sz - 1); + if (order < MIN_ORDER) { + order = MIN_ORDER; + } + + bool has_mem = true; + while (has_mem) { + has_mem = false; + // Find a block that is >= the requested order. If we can't find such a + // block the allocation fails. + for (unsigned i = MIN_ORDER; i <= MAX_ORDER; i++) { + if (free_lists[i]) { + // found a free page + uintptr_t pa = ka2pa((uintptr_t) free_lists[i]); + uintptr_t pn = pagenum(pa); + assert(pages[pn].free); + assert(pages[pn].order == i); + if (order == i) { + // The page matches the order so we can return it directly + ll_free_remove(free_lists[i], i); + pages[pn].free = false; + +#if (SANITIZE == 1) + // mark page allocated + asan_mark_memory(pa, sz, true); +#endif + + return (void *) pa2ka(pa); + } else if (i > order) { + // We found a block that is greater than the requested + // order so there are no blocks with the correct size. We + // can split this block and try again. + pages[pn].order = i - 1; + uintptr_t bpn = get_buddy(pn); + pages[bpn].order = i - 1; + pages[bpn].free = true; + + // update free lists + ll_free_remove(free_lists[i], i); + ll_free_insert(pn_to_free(pn), i - 1); + ll_free_insert(pn_to_free(bpn), i - 1); + + has_mem = true; + break; + } + } + } + } + + // allocation failed + return NULL; +} + +// Free a pointer previously returned by `kalloc`. Does nothing if `ptr == +// NULL`. +static void kfree_internal(void *ptr) { + if (!ptr || (char *) ptr < &_kheap_start) { + return; + } + + uintptr_t pa = ka2pa((uintptr_t) ptr); + uintptr_t pn = pagenum(pa); + + if (pages[pn].free) { + // page is already free + return; + } + + pages[pn].free = true; + uintptr_t bpn = get_buddy(pn); + unsigned order = pages[pn].order; + +#if (SANITIZE == 1) + // mark page free + asan_mark_memory(pa, (1 << pages[pn].order), false); +#endif + + while (bpn != (uintptr_t) -1 && pages[bpn].free && + pages[bpn].order == pages[pn].order) { + // coalesce + ll_free_remove(pn_to_free(bpn), pages[pn].order); + + if (valid(pn, pages[pn].order + 1)) { + order = ++pages[pn].order; + pages[bpn].order = 0; + bpn = get_buddy(pn); + } else if (valid(bpn, pages[pn].order + 1)) { + pages[pn].order = 0; + order = ++pages[bpn].order; + pn = bpn; + bpn = get_buddy(bpn); + } + } + + ll_free_insert(pn_to_free(pn), order); +} + +#ifdef RANDOMIZE_KMALLOC +void *kmalloc(size_t size) { + unsigned r = rand16() % 8; + void *ptrs[r]; + for (unsigned i = 0; i < r; i++) { + ptrs[i] = kmalloc_internal(size); + } + void *p = kmalloc_internal(size); + for (unsigned i = 0; i < r; i++) { + kfree(ptrs[i]); + } + return p; +} +#else +void *kmalloc(size_t size) { + return kmalloc_internal(size); +} +#endif + +void kfree(void *p) { + kfree_internal(p); +} diff --git a/kern/kmalloc.h b/kern/kmalloc.h new file mode 100644 index 0000000..2133a43 --- /dev/null +++ b/kern/kmalloc.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdint.h> +#include <string.h> + +#include "kern.h" + +void kmalloc_init(); +void *kmalloc(size_t size); +void kfree(void *p); + +static inline uintptr_t pagenum(uintptr_t pa) { + return pa / PAGESIZE; +} + +static inline uintptr_t pageaddr(uintptr_t pn) { + return pn * PAGESIZE; +} diff --git a/kern/ksan.c b/kern/ksan.c new file mode 100644 index 0000000..6724d1f --- /dev/null +++ b/kern/ksan.c @@ -0,0 +1,228 @@ +#if (SANITIZE == 1) + +#include <stdbool.h> +#include <stdint.h> + +#include "kern.h" +#include "kmalloc.h" +#include "vm.h" + +typedef struct { + const char *file; + uint32_t line; + uint32_t col; +} src_loc_t; + +typedef struct { + uint16_t kind; + uint16_t info; + char name[1]; +} type_desc_t; + +typedef struct { + src_loc_t loc; + const type_desc_t *array_type; + const type_desc_t *index_type; +} out_of_bounds_t; + +typedef struct { + src_loc_t loc; + const type_desc_t *lhs_type; + const type_desc_t *rhs_type; +} shift_out_of_bounds_t; + +typedef struct { + src_loc_t loc; + src_loc_t attr_loc; + int arg_index; +} nonnull_arg_t; + +typedef struct { + src_loc_t loc; + const type_desc_t *type; +} type_data_t; + +typedef struct { + src_loc_t loc; + type_desc_t *type; + uint8_t alignment; + uint8_t type_check_kind; +} type_mismatch_t; + +typedef type_data_t overflow_t; +typedef type_data_t invalid_value_t; +typedef type_data_t vla_bound_t; + +static void handle_overflow(overflow_t *data, + unsigned long lhs, + unsigned long rhs, + char op) { + panic("%s:%lu: integer overflow\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_add_overflow(overflow_t *data, + unsigned long a, + unsigned long b) { + handle_overflow(data, a, b, '+'); +} + +void __ubsan_handle_sub_overflow(overflow_t *data, + unsigned long a, + unsigned long b) { + handle_overflow(data, a, b, '-'); +} + +void __ubsan_handle_mul_overflow(overflow_t *data, + unsigned long a, + unsigned long b) { + handle_overflow(data, a, b, '*'); +} + +void __ubsan_handle_negate_overflow(overflow_t *data, unsigned long a) { + panic("%s:%lu: negate overflow\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_divrem_overflow(overflow_t *data, + unsigned long a, + unsigned long b) { + panic("%s:%lu: divrem overflow\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_t *data, + unsigned long a, + unsigned long b) { + panic("%s:%lu: shift out of bounds\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_type_mismatch(type_mismatch_t *data, unsigned long addr) { + panic("%s:%lu: type mismatch: %lx\n", data->loc.file, data->loc.line, addr); +} + +void __ubsan_handle_type_mismatch_v1(type_mismatch_t *data, + unsigned long addr) { + panic("%s:%lu: type mismatch v1: %lx, %d, %d\n", data->loc.file, + data->loc.line, addr, data->type_check_kind, data->alignment); +} + +void __ubsan_handle_out_of_bounds(out_of_bounds_t *data, unsigned long index) { + panic("%s:%lu: out of bounds\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_builtin_unreachable(src_loc_t *loc) { + panic("%s:%lu: unreachable\n", loc->file, loc->line); +} + +void __ubsan_handle_missing_return(src_loc_t *loc) { + panic("%s:%lu: missing return\n", loc->file, loc->line); +} + +void __ubsan_handle_vla_bound_not_positive(vla_bound_t *data, + unsigned long bound) { + panic("%s:%lu: vla bound not positive\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_load_invalid_value(invalid_value_t *data, + unsigned long val) { + panic("%s:%lu: load invalid value\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_nonnull_arg(nonnull_arg_t *data) { + panic("%s:%lu: nonnull arg\n", data->loc.file, data->loc.line); +} + +void __ubsan_handle_nonnull_return(src_loc_t *loc) { + panic("%s:%lu: nonnull return\n", loc->file, loc->line); +} + +void __ubsan_handle_pointer_overflow(src_loc_t *loc, + uintptr_t base, + uintptr_t result) { + panic("%s:%lu: pointer overflow\n", loc->file, loc->line); +} + +// each entry is 1 if alloced, 0 otherwise +static bool asan_pagemap[MEMSIZE_PHYSICAL / PAGESIZE]; + +static bool asan = false; + +static bool in_range(uintptr_t ka, char *start, char *end) { + return ka >= (uintptr_t) start && ka < (uintptr_t) end; +} + +static void asan_access(uintptr_t ka, size_t sz, bool write) { + if (!asan || ka >= MEMSIZE_PHYSICAL) { + return; + } + + extern char _ktext_start, _ktext_end; + if (write && in_range(ka, &_ktext_start, &_ktext_end)) { + panic("write to %x: in kernel text!\n", ka); + } + extern char _krodata_start, _krodata_end; + if (write && in_range(ka, &_krodata_start, &_krodata_end)) { + panic("write to %x: in kernel rodata!\n", ka); + } + + uintptr_t pn = pagenum(ka2pa(ka)); + if (!asan_pagemap[pn]) { + panic("invalid access at %x\n", ka); + } +} + +void asan_mark_memory(uintptr_t pa, size_t sz, bool alloced) { + uintptr_t pn = pagenum(pa); + asan_pagemap[pn] = alloced; +} + +static void asan_init() { + extern char _kheap_start; + uintptr_t heap_start = (uintptr_t) &_kheap_start; + for (uintptr_t pa = 0; pa < MEMSIZE_PHYSICAL; pa += PAGESIZE) { + uintptr_t pn = pagenum(pa); + // all pages below heap are alloced + asan_pagemap[pn] = pa < heap_start; + } +} + +void __asan_load1_noabort(unsigned long addr) { + asan_access(addr, 1, false); +} +void __asan_load2_noabort(unsigned long addr) { + asan_access(addr, 2, false); +} +void __asan_load4_noabort(unsigned long addr) { + asan_access(addr, 4, false); +} +void __asan_load8_noabort(unsigned long addr) { + asan_access(addr, 8, false); +} +void __asan_loadN_noabort(unsigned long addr, size_t sz) { + asan_access(addr, sz, false); +} + +void __asan_store1_noabort(unsigned long addr) { + asan_access(addr, 1, true); +} +void __asan_store2_noabort(unsigned long addr) { + asan_access(addr, 2, true); +} +void __asan_store4_noabort(unsigned long addr) { + asan_access(addr, 4, true); +} +void __asan_store8_noabort(unsigned long addr) { + asan_access(addr, 8, true); +} +void __asan_storeN_noabort(unsigned long addr, size_t sz) { + asan_access(addr, sz, true); +} + +void __asan_handle_no_return() {} +void __asan_before_dynamic_init(const char *module_name) {} +void __asan_after_dynamic_init() {} + +void asan_enable() { + asan_init(); + asan = true; +} + +#endif diff --git a/kern/ksan.h b/kern/ksan.h new file mode 100644 index 0000000..92460ae --- /dev/null +++ b/kern/ksan.h @@ -0,0 +1,6 @@ +#pragma once + +#include <string.h> + +void asan_enable(); +void asan_mark_memory(uintptr_t pa, size_t sz, bool alloc); diff --git a/kern/lib.h b/kern/lib.h new file mode 100644 index 0000000..803bf3b --- /dev/null +++ b/kern/lib.h @@ -0,0 +1,5 @@ +#pragma once + +static inline int msb(unsigned x) { + return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; +} diff --git a/kern/memmap.ld b/kern/memmap.ld new file mode 100644 index 0000000..44a41a4 --- /dev/null +++ b/kern/memmap.ld @@ -0,0 +1,55 @@ +ENTRY(_boot_start) + +SECTIONS +{ + .text.boot 0x8000 : { + _boot_start = .; + KEEP(*(.text.start.boot)) + KEEP(*(.text.boot)) + _boot_end = .; + . = ALIGN(8); + } + + /* rest of kernel is at high addresses */ + . = . | (1 << 31); + + /* load at low LMA with high VMA */ + .text : AT (ADDR(.text) & ~(1 << 31)) { + _ktext_start = .; + *(.text*) + _ktext_end = .; + . = ALIGN(8); + } + .rodata : { + _krodata_start = .; + *(.rodata*) + _krodata_end = .; + } + .data : { + _kdata_start = .; + *(.data*) + . = ALIGN(4); + _kdata_end = .; + } + + .bss : { + . = ALIGN(4); + _kbss_start = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _kbss_end = .; + . = ALIGN(8); + } + + .kstack : { + . += 8K; + } + + PROVIDE(kstack = .); + PROVIDE(kstack_phys = (. & ~(1 << 31))); + + _kheap_start = .; + + /DISCARD/ : { *(.eh_frame .note.GNU-stack) } +} diff --git a/kern/proc.c b/kern/proc.c new file mode 100644 index 0000000..cf519de --- /dev/null +++ b/kern/proc.c @@ -0,0 +1,70 @@ +#include "bits.h" +#include "proc.h" +#include "kern.h" +#include "kmalloc.h" +#include "vm.h" + +static pid_t id; + +proc_t procs[NPROC]; +proc_t *curproc; + +proc_t *proc_new(uint8_t *code_start, uint8_t *code_end) { + size_t codesz = code_end - code_start; + + proc_t *proc = &procs[id]; + proc->id = id++; + proc->pt = kalloc_pt(); + proc->state = PROC_RUNNABLE; + proc->code = code_start; + proc->codesz = codesz; + // map kernel into pt + for (uintptr_t pa = 0; pa < MEMSIZE_PHYSICAL; pa += SIZE_1MB) { + vm_map(proc->pt, pa2ka(pa), pa, PAGE_1MB, AP_KER_RW); + } + // map kernel devices + // TODO(masot) protect things + vm_map(proc->pt, pa2ka(0x20000000), 0x20000000, PAGE_1MB, AP_RW); + vm_map(proc->pt, pa2ka(0x20100000), 0x20100000, PAGE_1MB, AP_RW); + vm_map(proc->pt, pa2ka(0x20200000), 0x20200000, PAGE_1MB, AP_RW); + // map proc code into pt + void *pgs = kmalloc(proc->codesz); + memcpy(pgs, proc->code, proc->codesz); + for (size_t n = 0; n < proc->codesz; n += SIZE_4KB) { + vm_map(proc->pt, PROC_ENTRY + n, ka2pa((uintptr_t) pgs + n), PAGE_4KB, + AP_RW); + } + proc->regs.pc = PROC_ENTRY; + return proc; +} + +#include "asm.h" +#include "sys.h" +void __attribute__((noreturn)) proc_run(proc_t *proc) { + proc->state = PROC_RUNNING; + vm_set_pt(proc->pt); + curproc = proc; + + // NOTE: To use SPSR, need to be sure we are *NOT* in user/system mode. + // TODO(masot): add an assert like that + set_spsr(bits_set(get_cpsr(), 0, 4, 0b10000)); + asm volatile("ldm %0, {r0-r15}^" : : "r"(proc)); + while (1) { + } +} + +void swippityswap(regs_t *live_state, proc_t *new_thread, proc_t *old_thread) { + memcpy(&old_thread->regs, live_state, sizeof(regs_t)); + memcpy(live_state, &new_thread->regs, sizeof(regs_t)); +} + +void proc_scheduler_irq(regs_t *regs) { + pid_t curr_pid = curproc->id, next_pid = (curr_pid + 1) % id; + + swippityswap(regs, &procs[next_pid], &procs[curr_pid]); + + curproc->state = PROC_RUNNABLE; + curproc = &procs[next_pid]; + curproc->state = PROC_RUNNING; + vm_set_pt(curproc->pt); +} diff --git a/kern/proc.h b/kern/proc.h new file mode 100644 index 0000000..6f04825 --- /dev/null +++ b/kern/proc.h @@ -0,0 +1,51 @@ +#pragma once + +#include <stdint.h> +#include <string.h> + +#include "vm.h" + +#define PROC_ENTRY 0x8000 +#define NPROC 16 + +typedef struct { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t sp; + uint32_t lr; + uint32_t pc; +} regs_t; + +typedef enum { + PROC_FREE, + PROC_RUNNABLE, + PROC_RUNNING, +} proc_state_t; + +typedef struct { + regs_t regs; + uint32_t id; + pagetable_t *pt; + + uint8_t *code; + size_t codesz; + + proc_state_t state; +} proc_t; + +extern proc_t *curproc; + +proc_t *proc_new(uint8_t *code_start, uint8_t *code_end); +void proc_run(proc_t *proc); +void proc_scheduler_irq(regs_t *regs); diff --git a/kern/start.s b/kern/start.s new file mode 100644 index 0000000..ed2ce36 --- /dev/null +++ b/kern/start.s @@ -0,0 +1,29 @@ +#include "asm.h" + +#define prefetch_flush(reg) \ + mov reg, #0; \ + mcr p15, 0, reg, c7, c5, 4 + +.section ".text.start.boot" + +.globl _start +_start: + # force the mode to be system + mov r0, #SUPER_MODE + # disable interrupts + orr r0, r0, #(1 << 7) + msr cpsr, r0 + prefetch_flush(r1) + + ldr sp, =kstack_phys + # clear frame pointer + mov fp, #0 + bl cstart +.globl _hlt +_hlt: + b _hlt + +.globl stack_to_ka +stack_to_ka: + ldr sp, =kstack + bx lr @@ -1,5 +1,7 @@ #pragma once +#include <stdint.h> + #define CPU_FREQ_MHZ 700 #define SYS_MMU_ENABLE (1 << 0) @@ -18,6 +20,16 @@ static inline void dmb() { asm volatile("mcr p15, 0, r0, c7, c10, 5"); } +static inline void sys_set_vec_base(uintptr_t addr) { + asm volatile("mcr p15, 0, %0, c12, c0, 0" : : "r"(addr)); +} + +static inline uintptr_t sys_get_vec_base() { + uintptr_t addr; + asm volatile("mrc p15, 0, %0, c12, c0, 0" : "=r"(addr)); + return addr; +} + static inline void sys_prefetch_flush() { asm volatile("mcr p15, 0, r0, c7, c5, 4"); } @@ -182,6 +194,12 @@ static inline void sys_set_domain(unsigned reg) { asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r"(reg)); } +static inline unsigned sys_get_domain() { + unsigned reg; + asm volatile("mrc p15, 0, %0, c3, c0, 0" : "=r"(reg)); + return reg; +} + static inline void sys_set_tlb_base(unsigned base) { asm volatile("mcr p15, 0, %0, c2, c0, 0" : : "r"(base)); asm volatile("mcr p15, 0, %0, c2, c0, 1" : : "r"(base)); @@ -192,3 +210,33 @@ static inline unsigned get_dfar() { asm volatile("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfar)); return dfar; } + +static inline unsigned get_ifar() { + unsigned ifar = 0; + asm volatile("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifar)); + return ifar; +} + +static inline unsigned get_cpsr() { + unsigned cpsr = 0; + asm volatile("mrs %0, cpsr" : "=r"(cpsr)); + return cpsr; +} + +static inline void set_cpsr(unsigned cpsr) { + asm volatile("msr cpsr, %0" : : "r"(cpsr)); +} + +static inline unsigned get_spsr() { + unsigned spsr = 0; + asm volatile("mrs %0, spsr" : "=r"(spsr)); + return spsr; +} + +static inline void set_spsr(unsigned spsr) { + asm volatile("msr spsr, %0" : : "r"(spsr)); +} + +static inline void go_to_mode(unsigned mode) { + set_cpsr((get_cpsr() & ~0b11111) | mode); +} diff --git a/kern/syscall.c b/kern/syscall.c new file mode 100644 index 0000000..b3dab38 --- /dev/null +++ b/kern/syscall.c @@ -0,0 +1,61 @@ +#include <stdint.h> + +#include "kern.h" +#include "kmalloc.h" +#include "proc.h" +#include "sys.h" +#include "syscall_list.h" +#include "vm.h" + +#define VERBOSE_SYSCALLS 0 +#if VERBOSE_SYSCALLS +#define dprintf printf +#else +#define dprintf(...) +#endif + +unsigned syscall_alloc_page(uint32_t page_addr, uint32_t page_size) { + assert(page_addr == SYSCALL_ARG_ANY_PAGE); + dprintf("Got alloc page syscall for any page, 1MB long.\n"); + uintptr_t ptr = (uintptr_t) ka2pa((uintptr_t) kmalloc(page_size)); + dprintf("Giving back physical page %x\n", ptr); + return ptr; +} + +unsigned syscall_vm_map(uint32_t va, + uint32_t pa, + uint32_t flags, + uint32_t page_size) { + assert(flags == 0); + dprintf("Got VM_MAP syscall for va=%lx, pa=%lx, flags=%lx, 1MB.\n", va, pa, + flags); + // TODO(masot): FLAGS + vm_map(curproc->pt, va, pa, page_size, AP_RW); + vm_flushem(); + return 0; +} + +void syscall(regs_t *regs) { + unsigned sysno = regs->r0; + switch (sysno) { + case SYSCALL_EXIT: + printf("Exiting with exit code %lu\n", regs->r1); + reboot(); + break; + case SYSCALL_ALLOC_PAGE: + regs->r0 = syscall_alloc_page(regs->r1, regs->r2); + break; + case SYSCALL_DEALLOC_PAGE: + panic("SYSCALL_DEALLOC_PAGE"); + break; + case SYSCALL_VM_MAP: + regs->r0 = syscall_vm_map(regs->r1, regs->r2, regs->r3, regs->r4); + break; + case SYSCALL_GET_PID: + regs->r0 = curproc->id; + break; + default: + panic("unhandled syscall %d\n", sysno); + break; + } +} diff --git a/kern/syscall_list.h b/kern/syscall_list.h new file mode 100644 index 0000000..9e4366a --- /dev/null +++ b/kern/syscall_list.h @@ -0,0 +1,14 @@ +#pragma once + +#define SYSCALL_EXIT 0 +#define SYSCALL_ALLOC_PAGE 1 +#define SYSCALL_DEALLOC_PAGE 2 +#define SYSCALL_VM_MAP 3 +#define SYSCALL_GET_PID 4 + +// NOTE: DO NOT CHANGE THESE without changing vm.h +#define SYSCALL_ARG_ANY_PAGE 0 +#define SIZE_4KB (1 << 12) +#define SIZE_16KB (1 << 14) +#define SIZE_1MB (1 << 20) +#define SIZE_16MB (1 << 24) @@ -25,7 +25,8 @@ typedef struct { #define TIMER_CTRL_ENABLE (1 << 7) #define TIMER_CTRL_DISABLE (0 << 7) -static volatile timer_t* const timer = (timer_t*) 0x2000B400; +#define pa2ka(pa) (((pa) | (1UL << 31))) +static volatile timer_t *const timer = (timer_t *) pa2ka(0x2000b400); void timer_irq_load(uint32_t load) { timer->load = load; @@ -2,7 +2,6 @@ #include <stdbool.h> #include <stdint.h> - #include "sys.h" static inline void timer_init() { diff --git a/kern/u-syscall.h b/kern/u-syscall.h new file mode 100644 index 0000000..ed27522 --- /dev/null +++ b/kern/u-syscall.h @@ -0,0 +1,61 @@ +#pragma once + +#include <stdint.h> + +#include "syscall.h" + +static inline uintptr_t syscall_0(int sysno) { + register uintptr_t r0 asm("r0") = sysno; + asm volatile("swi 0" : "+r"(r0) : : "memory"); + return r0; +} +static inline uintptr_t syscall_1(int sysno, uintptr_t arg0) { + register uintptr_t r0 asm("r0") = sysno; + register uintptr_t r1 asm("r1") = arg0; + asm volatile("swi 0" : "+r"(r0), "+r"(r1) : : "memory"); + return r0; +} +static inline uintptr_t syscall_2(int sysno, uintptr_t arg0, uintptr_t arg1) { + register uintptr_t r0 asm("r0") = sysno; + register uintptr_t r1 asm("r1") = arg0; + register uintptr_t r2 asm("r2") = arg1; + asm volatile("swi 0" : "+r"(r0), "+r"(r1), "+r"(r2) : : "memory"); + return r0; +} +static inline uintptr_t syscall_3(int sysno, + uintptr_t arg0, + uintptr_t arg1, + uintptr_t arg2) { + register uintptr_t r0 asm("r0") = sysno; + register uintptr_t r1 asm("r1") = arg0; + register uintptr_t r2 asm("r2") = arg1; + register uintptr_t r3 asm("r3") = arg2; + asm volatile("swi 0" : "+r"(r0), "+r"(r1), "+r"(r2), "+r"(r3) : : "memory"); + return r0; +} + +static inline void exit() { + syscall_0(SYSCALL_EXIT); +} + +// Allocates a 4kB physical page at index i in [0, MAX_PAGES). If i is -1, tries +// to allocate any physical page. Returns the address of the allocated page; or +// returns a null pointer if the requested page does not exist or is already +// allocated, or if there are no available pages. +static inline void *alloc_page(int i) { + // Mark which process allocated the page. + return syscall_1(SYSCALL_ALLOC_PAGE, i); +} + +// Release the allocated physical page. The caller needs to have been previously +// allocated the physical page and not already deallocated it. Returns 0 if +// successful, otherwise -1. +static inline int dealloc_page(void *addr) { + return syscall_1(SYSCALL_DEALLOC_PAGE, addr); +} + +// Map the virtual address to the physical address. The caller must have been +// allocated the physical address. Returns 0 if successful, otherwise -1. +static inline int vm_map(uintptr_t va, uintptr_t pa, unsigned flags) { + return syscall_3(SYSCALL_VM_MAP, va, pa, flags); +} @@ -28,8 +28,8 @@ typedef struct { #define CLEAR_FIFOS (CLEAR_TX_FIFO | CLEAR_RX_FIFO) #define IIR_RESET ((0b11 << 6) | 1) -static volatile uint32_t* const aux_enables = (uint32_t*) 0x20215004; -static volatile aux_periphs_t* const uart = (aux_periphs_t*) 0x20215040; +static volatile uint32_t *const aux_enables = (uint32_t *) pa2ka(0x20215004); +static volatile aux_periphs_t *const uart = (aux_periphs_t *) pa2ka(0x20215040); void uart_init(unsigned baud) { gpio_set_func(GPIO_TX, GPIO_FUNC_ALT5); @@ -81,7 +81,7 @@ void uart_tx(uint8_t c) { dev_barrier(); } -void uart_putc(void* p, char c) { +void uart_putc(void *p, char c) { (void) p; uart_tx(c); } diff --git a/kern/uart.h b/kern/uart.h new file mode 100644 index 0000000..4efc756 --- /dev/null +++ b/kern/uart.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "libc/tinyprintf.h" + +void uart_init(unsigned baud); +bool uart_rx_empty(); +bool uart_can_tx(); +unsigned uart_rx_sz(); +uint8_t uart_rx(); +void uart_tx(uint8_t c); +bool uart_tx_empty(); +void uart_tx_flush(); + +// for tinyprintf +void uart_putc(void *p, char c); diff --git a/kern/vm.c b/kern/vm.c new file mode 100644 index 0000000..4327a42 --- /dev/null +++ b/kern/vm.c @@ -0,0 +1,74 @@ +#include "vm.h" +#include "bits.h" +#include "kern.h" +#include "kmalloc.h" +#include "sys.h" + +pagetable_t *kalloc_pt() { + pagetable_t *l1pt = (pagetable_t *) kmalloc(sizeof(pagetable_t)); + assert(l1pt); + memset(l1pt, 0, sizeof(pagetable_t)); + return l1pt; +} + +static void init_second_level(pde_t *pde) { + pte_small_t *pgtbl = kmalloc(256 * sizeof(pte_small_t)); + assert(pgtbl); + memset(pgtbl, 0, 256 * sizeof(pte_small_t)); + pde->addr = ka2pa((uintptr_t) pgtbl) >> 10; + pde->tag = 0b01; +} + +void vm_map(pagetable_t *pt, + uintptr_t va, + uintptr_t pa, + pg_typ_t typ, + ap_t prot) { + unsigned idx = va >> 20; + l1pte_t *l1pte = &pt->entries[idx]; + + // TODO: allow remapping + assert(l1pte->pde.tag == 0); + + switch (typ) { + case PAGE_UNMAPPED: + l1pte->pde.tag = 0b00; + break; + case PAGE_1MB: + l1pte->pte_1mb.tag = 0b10; + l1pte->pte_1mb.sec_base_addr = pa >> 20; + l1pte->pte_1mb.ap = prot; + break; + case PAGE_4KB: + if (l1pte->pde.tag == 0b00) { + init_second_level(&l1pte->pde); + } + pte_small_t *l2pt = + (pte_small_t *) pa2ka((uintptr_t) l1pte->pde.addr << 10); + pte_small_t *l2pte = &l2pt[bits_get(va, 12, 19)]; + l2pte->addr = pa >> 12; + l2pte->ap = prot; + l2pte->sz = 1; + break; + default: + panic("invalid page type: %d\n", typ); + } +} + +void vm_unmap(pagetable_t *pt, uintptr_t va) { + vm_map(pt, va, 0, PAGE_UNMAPPED, 0); +} + +void vm_set_pt(pagetable_t *pt) { + sys_set_tlb_base(ka2pa((uintptr_t) pt)); + sys_invalidate_tlb(); + sys_clean_and_invalidate_cache(); +} + +void vm_flushem() { + sys_clean_and_invalidate_cache(); + sys_flush_btb(); + sys_invalidate_tlb(); + sys_prefetch_flush(); + dsb(); +} @@ -2,6 +2,9 @@ #include <stdint.h> +#define pa2ka(pa) (((pa) | (1UL << 31))) +#define ka2pa(ka) (((ka) & ~(1UL << 31))) + typedef struct { unsigned tag : 2; unsigned b : 1; @@ -60,11 +63,28 @@ typedef struct { } pte_large_t; _Static_assert(sizeof(pte_large_t) == 4, "invalid size for pte_large_t"); -enum { +typedef union { + pde_t pde; + pte_1mb_t pte_1mb; +} l1pte_t; +_Static_assert(sizeof(l1pte_t) == 4, "invalid size for l1pte_t"); + +typedef union { + pte_small_t pte_4k; + pte_large_t pte_16k; +} l2pte_t; +_Static_assert(sizeof(l2pte_t) == 4, "invalid size for l2pte_t"); + +typedef struct { + l1pte_t entries[4096]; +} pagetable_t; + +typedef enum { AP_RW = 0b11, AP_NO_ACCESS = 0b00, AP_RO = 0b10, -}; + AP_KER_RW = 0b01, +} ap_t; enum { DOM_NO_ACCESS = 0b00, // any access causes fault @@ -73,6 +93,26 @@ enum { DOM_MANAGER = 0b11, // TLB access bits are ignored }; -void vm_init(); -void vm_map(uintptr_t va, uintptr_t pa, unsigned flags); -void vm_enable(); +// NOTE: DO NOT CHANGE THESE without changing syscall_list.h +#define SIZE_4KB (1 << 12) +#define SIZE_16KB (1 << 14) +#define SIZE_1MB (1 << 20) +#define SIZE_16MB (1 << 24) + +typedef enum { + PAGE_UNMAPPED = 0, + PAGE_4KB = SIZE_4KB, + PAGE_16KB = SIZE_16KB, + PAGE_1MB = SIZE_1MB, + PAGE_16MB = SIZE_16MB, +} pg_typ_t; + +pagetable_t *kalloc_pt(); +void vm_map(pagetable_t *pt, + uintptr_t va, + uintptr_t pa, + pg_typ_t typ, + ap_t prot); +void vm_unmap(pagetable_t *pt, uintptr_t va); +void vm_set_pt(pagetable_t *pt); +void vm_flushem(); diff --git a/kmalloc.c b/kmalloc.c deleted file mode 100644 index ae86b3f..0000000 --- a/kmalloc.c +++ /dev/null @@ -1,238 +0,0 @@ -#include <stdbool.h> -#include <stdint.h> - -#include "kmalloc.h" -#include "pios.h" - -union align { - double d; - void* p; - void (*fp)(void); -}; - -typedef union free_hdr { /* block header */ - struct { - union free_hdr* ptr; /* next block if on free list */ - unsigned size; /* size of this block */ - } s; - union align x; /* force alignment of blocks */ -} free_hdr_t; - -extern char __heap_start__; -uintptr_t heap_end = (uintptr_t) &__heap_start__; - -static inline uintptr_t align_off(uintptr_t ptr, size_t align) { - return ((~ptr) + 1) & (align - 1); -} - -static void* sbrk(size_t size) { - void* ret = (void*) heap_end; - heap_end += size; - heap_end += align_off(heap_end, __alignof__(free_hdr_t)); - return ret; -} - -static free_hdr_t base; /* empty list to get started */ -static free_hdr_t* freep = NULL; /* start of free list */ - -static void kr_free(void* ap); - -#define NALLOC 1024 /* minimum #units to request */ -/* morecore: ask system for more memory */ -static free_hdr_t* morecore(unsigned nu) { - char* cp; - free_hdr_t* up; - if (nu < NALLOC) - nu = NALLOC; - cp = sbrk(nu * sizeof(free_hdr_t)); - if (cp == (char*) -1) /* no space at all */ - return NULL; - up = (free_hdr_t*) cp; - up->s.size = nu; - kr_free((void*) (up + 1)); - return freep; -} - -static void* kr_malloc(size_t nbytes) { - free_hdr_t *p, *prevp; - unsigned nunits; - nunits = (nbytes + sizeof(free_hdr_t) - 1) / sizeof(free_hdr_t) + 1; - if ((prevp = freep) == NULL) { /* no free list yet */ - base.s.ptr = freep = prevp = &base; - base.s.size = 0; - } - for (p = prevp->s.ptr;; prevp = p, p = p->s.ptr) { - if (p->s.size >= nunits) { /* big enough */ - if (p->s.size == nunits) /* exactly */ - prevp->s.ptr = p->s.ptr; - else { /* allocate tail end */ - p->s.size -= nunits; - p += p->s.size; - p->s.size = nunits; - } - freep = prevp; - return (void*) (p + 1); - } - if (p == freep) /* wrapped around free list */ - if ((p = morecore(nunits)) == NULL) - return NULL; /* none left */ - } -} - -/* free: put block ap in free list */ -static void kr_free(void* ap) { - free_hdr_t *bp, *p; - bp = (free_hdr_t*) ap - 1; /* point to block header */ - for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) - if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) - break; /* freed block at start or end of arena */ - if (bp + bp->s.size == p->s.ptr) { /* join to upper nbr */ - bp->s.size += p->s.ptr->s.size; - bp->s.ptr = p->s.ptr->s.ptr; - } else - bp->s.ptr = p->s.ptr; - if (p + p->s.size == bp) { /* join to lower nbr */ - p->s.size += bp->s.size; - p->s.ptr = bp->s.ptr; - } else - p->s.ptr = bp; - freep = p; -} - -#if (SANITIZE == 0) - -void* kmalloc(size_t sz) { - return kr_malloc(sz); -} - -void kfree(void* p) { - kr_free(p); -} - -#else - -typedef struct asan_hdr { - size_t size; - struct asan_hdr* next; - struct asan_hdr* prev; -} asan_hdr_t; - -static asan_hdr_t* alloc_list; - -static void ll_insert(asan_hdr_t* n) { - n->next = alloc_list; - n->prev = NULL; - if (alloc_list) - alloc_list->prev = n; - alloc_list = n; -} - -static void ll_remove(asan_hdr_t* n) { - if (n->next) - n->next->prev = n->prev; - if (n->prev) - n->prev->next = n->next; - else - alloc_list = n->next; -} - -static char* blk_start(asan_hdr_t* h) { - return (char*) h + sizeof(asan_hdr_t); -} - -static char* blk_end(asan_hdr_t* h) { - return (char*) h + sizeof(asan_hdr_t) + h->size; -} - -void* kmalloc(size_t sz) { - asan_hdr_t* h = (asan_hdr_t*) kr_malloc(sz + sizeof(asan_hdr_t)); - h->size = sz; - ll_insert(h); - return (void*) blk_start(h); -} - -void kfree(void* p) { - asan_hdr_t* h = (asan_hdr_t*) ((char*) p - sizeof(asan_hdr_t)); - ll_remove(h); - kr_free(h); -} - -static bool asan = false; - -static bool in_range(char* addr, char* start, char* end) { - return addr >= start && addr < end; -} - -static void asan_access(unsigned long addr, size_t sz, bool write) { - if (!asan) { - return; - } - - extern char __code_start__, __code_end__; - if (write && in_range((char*) addr, &__code_start__, &__code_end__)) { - panic("write to code segment: 0x%lx\n", addr); - } - extern char __rodata_start__, __rodata_end__; - if (write && in_range((char*) addr, &__rodata_start__, &__rodata_end__)) { - panic("write to read-only data segment: 0x%lx\n", addr); - } - extern char __heap_start__; - extern uintptr_t heap_end; - if (in_range((char*) addr, &__heap_start__, (char*) heap_end)) { - asan_hdr_t* h = alloc_list; - while (h) { - if (in_range((char*) addr, blk_start(h), blk_end(h))) { - return; - } - h = h->next; - } - panic("illegal heap memory access: 0x%lx\n", addr); - } -} - -void __asan_load1_noabort(unsigned long addr) { - asan_access(addr, 1, false); -} -void __asan_load2_noabort(unsigned long addr) { - asan_access(addr, 2, false); -} -void __asan_load4_noabort(unsigned long addr) { - asan_access(addr, 4, false); -} -void __asan_load8_noabort(unsigned long addr) { - asan_access(addr, 8, false); -} -void __asan_loadN_noabort(unsigned long addr, size_t sz) { - asan_access(addr, sz, false); -} - -void __asan_store1_noabort(unsigned long addr) { - asan_access(addr, 1, true); -} -void __asan_store2_noabort(unsigned long addr) { - asan_access(addr, 2, true); -} -void __asan_store4_noabort(unsigned long addr) { - asan_access(addr, 4, true); -} -void __asan_store8_noabort(unsigned long addr) { - asan_access(addr, 8, true); -} -void __asan_storeN_noabort(unsigned long addr, size_t sz) { - asan_access(addr, sz, true); -} - -void __asan_handle_no_return() {} -void __asan_before_dynamic_init(const char* module_name) {} -void __asan_after_dynamic_init() {} - -void asan_enable() { - asan = true; -} - -#endif - -void* kmalloc_aligned(size_t sz, size_t align) { - uintptr_t x = (uintptr_t) kmalloc(sz + align); - return (void*) (x + align_off(x, align)); -} diff --git a/kmalloc.h b/kmalloc.h deleted file mode 100644 index 32907ed..0000000 --- a/kmalloc.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include <string.h> - -void* kmalloc(size_t size); -void* kmalloc_aligned(size_t size, size_t align); -void kfree(void* p); @@ -1,132 +0,0 @@ -#include <stdbool.h> -#include <stdint.h> - -#include "pios.h" - -#if (SANITIZE == 1) - -typedef struct { - const char* file; - uint32_t line; - uint32_t col; -} src_loc_t; - -typedef struct { - uint16_t kind; - uint16_t info; - char name[1]; -} type_desc_t; - -typedef struct { - src_loc_t loc; - const type_desc_t* array_type; - const type_desc_t* index_type; -} out_of_bounds_t; - -typedef struct { - src_loc_t loc; - const type_desc_t* lhs_type; - const type_desc_t* rhs_type; -} shift_out_of_bounds_t; - -typedef struct { - src_loc_t loc; - src_loc_t attr_loc; - int arg_index; -} nonnull_arg_t; - -typedef struct { - src_loc_t loc; - const type_desc_t* type; -} type_data_t; - -typedef type_data_t overflow_t; -typedef type_data_t invalid_value_t; -typedef type_data_t vla_bound_t; - -static void handle_overflow(overflow_t* data, - unsigned long lhs, - unsigned long rhs, - char op) { - panic("%s:%lu: integer overflow\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_add_overflow(overflow_t* data, - unsigned long a, - unsigned long b) { - handle_overflow(data, a, b, '+'); -} - -void __ubsan_handle_sub_overflow(overflow_t* data, - unsigned long a, - unsigned long b) { - handle_overflow(data, a, b, '-'); -} - -void __ubsan_handle_mul_overflow(overflow_t* data, - unsigned long a, - unsigned long b) { - handle_overflow(data, a, b, '*'); -} - -void __ubsan_handle_negate_overflow(overflow_t* data, unsigned long a) { - panic("%s:%lu: negate overflow\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_divrem_overflow(overflow_t* data, - unsigned long a, - unsigned long b) { - panic("%s:%lu: divrem overflow\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_t* data, - unsigned long a, - unsigned long b) { - panic("%s:%lu: shift out of bounds\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_type_mismatch() { - panic("type mismatch\n"); -} - -void __ubsan_handle_type_mismatch_v1() { - panic("type mismatch v1\n"); -} - -void __ubsan_handle_out_of_bounds(out_of_bounds_t* data, unsigned long index) { - panic("%s:%lu: out of bounds\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_builtin_unreachable(src_loc_t* loc) { - panic("%s:%lu: unreachable\n", loc->file, loc->line); -} - -void __ubsan_handle_missing_return(src_loc_t* loc) { - panic("%s:%lu: missing return\n", loc->file, loc->line); -} - -void __ubsan_handle_vla_bound_not_positive(vla_bound_t* data, - unsigned long bound) { - panic("%s:%lu: vla bound not positive\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_load_invalid_value(invalid_value_t* data, - unsigned long val) { - panic("%s:%lu: load invalid value\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_nonnull_arg(nonnull_arg_t* data) { - panic("%s:%lu: nonnull arg\n", data->loc.file, data->loc.line); -} - -void __ubsan_handle_nonnull_return(src_loc_t* loc) { - panic("%s:%lu: nonnull return\n", loc->file, loc->line); -} - -void __ubsan_handle_pointer_overflow(src_loc_t* loc, - uintptr_t base, - uintptr_t result) { - panic("%s:%lu: pointer overflow\n", loc->file, loc->line); -} - -#endif @@ -1,7 +0,0 @@ -#pragma once - -#include <string.h> - -void asan_enable(); -void* asan_kmalloc(size_t sz); -void asan_kfree(void* p); diff --git a/libc/libc.c b/libc/libc.c index cf7e3e4..c3b1f53 100644 --- a/libc/libc.c +++ b/libc/libc.c @@ -1,18 +1,18 @@ #include <stddef.h> -void* memchr(const void* s, int c, size_t n) { - const unsigned char* sp = s; +void *memchr(const void *s, int c, size_t n) { + const unsigned char *sp = s; while (n--) { if (*sp == (unsigned char) c) - return (void*) sp; + return (void *) sp; sp++; } return NULL; } -int memcmp(const void* s1, const void* s2, size_t n) { +int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *c1 = s1, *c2 = s2; int d = 0; @@ -25,9 +25,9 @@ int memcmp(const void* s1, const void* s2, size_t n) { return d; } -void* memcpy(void* dst, const void* src, size_t n) { - const char* p = src; - char* q = dst; +void *memcpy(void *dst, const void *src, size_t n) { + const char *p = src; + char *q = dst; while (n--) { *q++ = *p++; } @@ -35,9 +35,9 @@ void* memcpy(void* dst, const void* src, size_t n) { return dst; } -void* memmove(void* dst, const void* src, size_t count) { - char* a = dst; - const char* b = src; +void *memmove(void *dst, const void *src, size_t count) { + char *a = dst; + const char *b = src; if (src == dst) return dst; @@ -55,8 +55,8 @@ void* memmove(void* dst, const void* src, size_t count) { return dst; } -void* memset(void* dst, int c, size_t n) { - char* q = dst; +void *memset(void *dst, int c, size_t n) { + char *q = dst; while (n--) { *q++ = c; @@ -65,9 +65,9 @@ void* memset(void* dst, int c, size_t n) { return dst; } -void memswap(void* m1, void* m2, size_t n) { - char* p = m1; - char* q = m2; +void memswap(void *m1, void *m2, size_t n) { + char *p = m1; + char *q = m2; char tmp; while (n--) { @@ -90,7 +90,7 @@ static inline size_t newgap(size_t gap) { return gap; } -int strcmp(const char* a, const char* b) { +int strcmp(const char *a, const char *b) { while (1) { unsigned char ac = *a, bc = *b; if (ac == 0 || bc == 0 || ac != bc) { @@ -100,7 +100,7 @@ int strcmp(const char* a, const char* b) { } } -size_t strlen(const char* p) { +size_t strlen(const char *p) { size_t ret; for (ret = 0; p[ret]; ++ret) ; diff --git a/libc/rand.c b/libc/rand.c new file mode 100644 index 0000000..9e6fdd0 --- /dev/null +++ b/libc/rand.c @@ -0,0 +1,18 @@ +// TODO improve rand implementation, this one is from libpi + +static unsigned short lfsr = 0xACE1u; +static unsigned bit; + +unsigned short rand16() { + bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1; + lfsr = (lfsr >> 1) | (bit << 15); + return lfsr; +} + +unsigned long rand32() { + return (rand16() << 16) | rand16(); +} + +void rand_seed(unsigned seed) { + lfsr = seed; +} diff --git a/libc/rand.h b/libc/rand.h new file mode 100644 index 0000000..6ce3bed --- /dev/null +++ b/libc/rand.h @@ -0,0 +1,3 @@ +void rand_seed(unsigned seed); +unsigned long rand32(void); +unsigned short rand16(void); diff --git a/libc/tinyprintf.c b/libc/tinyprintf.c index a7a528d..c169ac9 100644 --- a/libc/tinyprintf.c +++ b/libc/tinyprintf.c @@ -76,15 +76,15 @@ struct param { unsigned int width; /**< field width */ char sign; /**< The sign to display (if any) */ unsigned int base; /**< number base (e.g.: 8, 10, 16) */ - char* bf; /**< Buffer to output */ + char *bf; /**< Buffer to output */ }; #ifdef PRINTF_LONG_LONG_SUPPORT static void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, - struct param* p) { + struct param *p) { int n = 0; unsigned long long int d = 1; - char* bf = p->bf; + char *bf = p->bf; while (num / d >= p->base) d *= p->base; while (d != 0) { @@ -99,7 +99,7 @@ static void _TFP_GCC_NO_INLINE_ ulli2a(unsigned long long int num, *bf = 0; } -static void lli2a(long long int num, struct param* p) { +static void lli2a(long long int num, struct param *p) { if (num < 0) { num = -num; p->sign = '-'; @@ -109,10 +109,10 @@ static void lli2a(long long int num, struct param* p) { #endif #ifdef PRINTF_LONG_SUPPORT -static void uli2a(unsigned long int num, struct param* p) { +static void uli2a(unsigned long int num, struct param *p) { int n = 0; unsigned long int d = 1; - char* bf = p->bf; + char *bf = p->bf; while (num / d >= p->base) d *= p->base; while (d != 0) { @@ -127,7 +127,7 @@ static void uli2a(unsigned long int num, struct param* p) { *bf = 0; } -static void li2a(long num, struct param* p) { +static void li2a(long num, struct param *p) { if (num < 0) { num = -num; p->sign = '-'; @@ -136,10 +136,10 @@ static void li2a(long num, struct param* p) { } #endif -static void ui2a(unsigned int num, struct param* p) { +static void ui2a(unsigned int num, struct param *p) { int n = 0; unsigned int d = 1; - char* bf = p->bf; + char *bf = p->bf; while (num / d >= p->base) d *= p->base; while (d != 0) { @@ -154,7 +154,7 @@ static void ui2a(unsigned int num, struct param* p) { *bf = 0; } -static void i2a(int num, struct param* p) { +static void i2a(int num, struct param *p) { if (num < 0) { num = -num; p->sign = '-'; @@ -173,8 +173,8 @@ static int a2d(char ch) { return -1; } -static char a2u(char ch, const char** src, int base, unsigned int* nump) { - const char* p = *src; +static char a2u(char ch, const char **src, int base, unsigned int *nump) { + const char *p = *src; unsigned int num = 0; int digit; while ((digit = a2d(ch)) >= 0) { @@ -188,10 +188,10 @@ static char a2u(char ch, const char** src, int base, unsigned int* nump) { return ch; } -static void putchw(void* putp, putcf putf, struct param* p) { +static void putchw(void *putp, putcf putf, struct param *p) { char ch; int n = p->width; - char* bf = p->bf; + char *bf = p->bf; /* Number of filling characters */ while (*bf++ && n > 0) @@ -239,7 +239,7 @@ static void putchw(void* putp, putcf putf, struct param* p) { } } -void tfp_format(void* putp, putcf putf, const char* fmt, va_list va) { +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va) { struct param p; #ifdef PRINTF_LONG_SUPPORT char bf[23]; /* long = 64b on some architectures */ @@ -266,17 +266,17 @@ void tfp_format(void* putp, putcf putf, const char* fmt, va_list va) { /* Flags */ while ((ch = *(fmt++))) { switch (ch) { - case '-': - p.align_left = 1; - continue; - case '0': - p.lz = 1; - continue; - case '#': - p.alt = 1; - continue; - default: - break; + case '-': + p.align_left = 1; + continue; + case '0': + p.lz = 1; + continue; + case '#': + p.alt = 1; + continue; + default: + break; } break; } @@ -324,84 +324,84 @@ void tfp_format(void* putp, putcf putf, const char* fmt, va_list va) { } #endif switch (ch) { - case 0: - goto abort; - case 'u': - p.base = 10; + case 0: + goto abort; + case 'u': + p.base = 10; #ifdef PRINTF_LONG_SUPPORT #ifdef PRINTF_LONG_LONG_SUPPORT - if (2 == lng) - ulli2a(va_arg(va, unsigned long long int), &p); - else + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else #endif - if (1 == lng) - uli2a(va_arg(va, unsigned long int), &p); - else + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else #endif - ui2a(va_arg(va, unsigned int), &p); - putchw(putp, putf, &p); - break; - case 'd': - case 'i': - p.base = 10; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'd': + case 'i': + p.base = 10; #ifdef PRINTF_LONG_SUPPORT #ifdef PRINTF_LONG_LONG_SUPPORT - if (2 == lng) - lli2a(va_arg(va, long long int), &p); - else + if (2 == lng) + lli2a(va_arg(va, long long int), &p); + else #endif - if (1 == lng) - li2a(va_arg(va, long int), &p); - else + if (1 == lng) + li2a(va_arg(va, long int), &p); + else #endif - i2a(va_arg(va, int), &p); - putchw(putp, putf, &p); - break; + i2a(va_arg(va, int), &p); + putchw(putp, putf, &p); + break; #ifdef SIZEOF_POINTER - case 'p': - p.alt = 1; + case 'p': + p.alt = 1; #if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT - lng = 0; + lng = 0; #elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG - lng = 1; + lng = 1; #elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG - lng = 2; + lng = 2; #endif #endif - case 'x': - case 'X': - p.base = 16; - p.uc = (ch == 'X') ? 1 : 0; + case 'x': + case 'X': + p.base = 16; + p.uc = (ch == 'X') ? 1 : 0; #ifdef PRINTF_LONG_SUPPORT #ifdef PRINTF_LONG_LONG_SUPPORT - if (2 == lng) - ulli2a(va_arg(va, unsigned long long int), &p); - else + if (2 == lng) + ulli2a(va_arg(va, unsigned long long int), &p); + else #endif - if (1 == lng) - uli2a(va_arg(va, unsigned long int), &p); - else + if (1 == lng) + uli2a(va_arg(va, unsigned long int), &p); + else #endif - ui2a(va_arg(va, unsigned int), &p); - putchw(putp, putf, &p); - break; - case 'o': - p.base = 8; ui2a(va_arg(va, unsigned int), &p); - putchw(putp, putf, &p); - break; - case 'c': - putf(putp, (char) (va_arg(va, int))); - break; - case 's': - p.bf = va_arg(va, char*); - putchw(putp, putf, &p); - p.bf = bf; - break; - case '%': - putf(putp, ch); - default: - break; + putchw(putp, putf, &p); + break; + case 'o': + p.base = 8; + ui2a(va_arg(va, unsigned int), &p); + putchw(putp, putf, &p); + break; + case 'c': + putf(putp, (char) (va_arg(va, int))); + break; + case 's': + p.bf = va_arg(va, char *); + putchw(putp, putf, &p); + p.bf = bf; + break; + case '%': + putf(putp, ch); + default: + break; } } } @@ -410,14 +410,14 @@ abort:; #if TINYPRINTF_DEFINE_TFP_PRINTF static putcf stdout_putf; -static void* stdout_putp; +static void *stdout_putp; -void init_printf(void* putp, putcf putf) { +void init_printf(void *putp, putcf putf) { stdout_putf = putf; stdout_putp = putp; } -void tfp_printf(char* fmt, ...) { +void tfp_printf(char *fmt, ...) { va_list va; va_start(va, fmt); tfp_format(stdout_putp, stdout_putf, fmt, va); @@ -428,18 +428,18 @@ void tfp_printf(char* fmt, ...) { #if TINYPRINTF_DEFINE_TFP_SPRINTF struct _vsnprintf_putcf_data { size_t dest_capacity; - char* dest; + char *dest; size_t num_chars; }; -static void _vsnprintf_putcf(void* p, char c) { - struct _vsnprintf_putcf_data* data = (struct _vsnprintf_putcf_data*) p; +static void _vsnprintf_putcf(void *p, char c) { + struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data *) p; if (data->num_chars < data->dest_capacity) data->dest[data->num_chars] = c; data->num_chars++; } -int tfp_vsnprintf(char* str, size_t size, const char* format, va_list ap) { +int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap) { struct _vsnprintf_putcf_data data; if (size < 1) @@ -458,7 +458,7 @@ int tfp_vsnprintf(char* str, size_t size, const char* format, va_list ap) { return data.num_chars; } -int tfp_snprintf(char* str, size_t size, const char* format, ...) { +int tfp_snprintf(char *str, size_t size, const char *format, ...) { va_list ap; int retval; @@ -469,16 +469,16 @@ int tfp_snprintf(char* str, size_t size, const char* format, ...) { } struct _vsprintf_putcf_data { - char* dest; + char *dest; size_t num_chars; }; -static void _vsprintf_putcf(void* p, char c) { - struct _vsprintf_putcf_data* data = (struct _vsprintf_putcf_data*) p; +static void _vsprintf_putcf(void *p, char c) { + struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data *) p; data->dest[data->num_chars++] = c; } -int tfp_vsprintf(char* str, const char* format, va_list ap) { +int tfp_vsprintf(char *str, const char *format, va_list ap) { struct _vsprintf_putcf_data data; data.dest = str; data.num_chars = 0; @@ -487,7 +487,7 @@ int tfp_vsprintf(char* str, const char* format, va_list ap) { return data.num_chars; } -int tfp_sprintf(char* str, const char* format, ...) { +int tfp_sprintf(char *str, const char *format, ...) { va_list ap; int retval; diff --git a/libc/tinyprintf.h b/libc/tinyprintf.h index d61ea96..df3e7b7 100644 --- a/libc/tinyprintf.h +++ b/libc/tinyprintf.h @@ -142,7 +142,7 @@ regs Kusti, 23.10.2004 extern "C" { #endif -typedef void (*putcf)(void*, char); +typedef void (*putcf)(void *, char); /* 'tfp_format' really is the central function for all tinyprintf. For @@ -154,14 +154,14 @@ typedef void (*putcf)(void*, char); The 'tfp_printf' and 'tfp_sprintf' functions simply define their own callback and pass to it the right 'putp' it is expecting. */ -void tfp_format(void* putp, putcf putf, const char* fmt, va_list va); +void tfp_format(void *putp, putcf putf, const char *fmt, va_list va); #if TINYPRINTF_DEFINE_TFP_SPRINTF -int tfp_vsnprintf(char* str, size_t size, const char* fmt, va_list ap); -int tfp_snprintf(char* str, size_t size, const char* fmt, ...) +int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int tfp_snprintf(char *str, size_t size, const char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(3, 4); -int tfp_vsprintf(char* str, const char* fmt, va_list ap); -int tfp_sprintf(char* str, const char* fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); +int tfp_vsprintf(char *str, const char *fmt, va_list ap); +int tfp_sprintf(char *str, const char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); #if TINYPRINTF_OVERRIDE_LIBC #define vsnprintf tfp_vsnprintf #define snprintf tfp_snprintf @@ -171,8 +171,8 @@ int tfp_sprintf(char* str, const char* fmt, ...) _TFP_SPECIFY_PRINTF_FMT(2, 3); #endif #if TINYPRINTF_DEFINE_TFP_PRINTF -void init_printf(void* putp, putcf putf); -void tfp_printf(char* fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); +void init_printf(void *putp, putcf putf); +void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2); #if TINYPRINTF_OVERRIDE_LIBC #define printf tfp_printf #endif diff --git a/pid_os/Makefile b/pid_os/Makefile new file mode 100644 index 0000000..614b73c --- /dev/null +++ b/pid_os/Makefile @@ -0,0 +1,32 @@ +include ../defs.mk + +CFLAGS += -MMD + +MEMMAP = memmap.ld +INCLUDE = -I$(KERN) -I$(PIOS) +CFLAGS += $(INCLUDE) +ASFLAGS += $(INCLUDE) +CPPFLAGS += $(INCLUDE) +DEP = $(KERN_OBJ:.o=.d) + +OBJ = pidos.o start.o uart.o gpio.o ../libc/tinyprintf.o + +all: pidos.bin + +pidos.elf: $(OBJ) + $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +$(PIOS)/kern/p-pidos.o: pidos.bin + $(LD) -r -b binary -o $@ $< + +exostall: $(PIOS)/kern/p-pidos.o + +clean: + rm -f *.d *.list *.o *.elf *.bin + +-include $(DEP) + +format: + clang-format -i $(PIOS_CSRC) $(PIOS_HSRC) + +.PHONY: format all install diff --git a/pid_os/bits.h b/pid_os/bits.h new file mode 100644 index 0000000..f0f16a2 --- /dev/null +++ b/pid_os/bits.h @@ -0,0 +1,78 @@ +#pragma once + +#include <stdint.h> + +static inline uint32_t bit_clr(uint32_t x, unsigned bit) { + return x & ~(1 << bit); +} + +static inline uint32_t bit_set(uint32_t x, unsigned bit) { + return x | (1 << bit); +} + +static inline uint32_t bit_assign(uint32_t x, unsigned bit, unsigned val) { + x = bit_clr(x, bit); + return x | (val << bit); +} + +#define bit_isset bit_is_on +#define bit_get bit_is_on + +static inline unsigned bit_is_on(uint32_t x, unsigned bit) { + return (x >> bit) & 1; +} +static inline unsigned bit_is_off(uint32_t x, unsigned bit) { + return bit_is_on(x, bit) == 0; +} + +static inline uint32_t bits_mask(unsigned nbits) { + if (nbits == 32) + return ~0; + return (1 << nbits) - 1; +} + +static inline uint32_t bits_get(uint32_t x, unsigned lb, unsigned ub) { + return (x >> lb) & bits_mask(ub - lb + 1); +} + +static inline uint32_t bits_clr(uint32_t x, unsigned lb, unsigned ub) { + uint32_t mask = bits_mask(ub - lb + 1); + return x & ~(mask << lb); +} + +static inline uint32_t bits_set(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t v) { + return bits_clr(x, lb, ub) | (v << lb); +} + +static inline unsigned bits_eq(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t val) { + return bits_get(x, lb, ub) == val; +} + +static inline unsigned bit_count(uint32_t x) { + unsigned cnt = 0; + for (unsigned i = 0; i < 32; i++) + if (bit_is_on(x, i)) + cnt++; + return cnt; +} + +static inline uint32_t bits_union(uint32_t x, uint32_t y) { + return x | y; +} + +static inline uint32_t bits_intersect(uint32_t x, uint32_t y) { + return x & y; +} +static inline uint32_t bits_not(uint32_t x) { + return ~x; +} + +static inline uint32_t bits_diff(uint32_t A, uint32_t B) { + return bits_intersect(A, bits_not(B)); +} diff --git a/pid_os/dev.h b/pid_os/dev.h new file mode 100644 index 0000000..1f644f7 --- /dev/null +++ b/pid_os/dev.h @@ -0,0 +1,5 @@ +#pragma once + +static inline void dev_barrier() { + asm volatile("mcr p15, 0, r0, c7, c10, 4"); +} diff --git a/pid_os/gpio.c b/pid_os/gpio.c new file mode 100644 index 0000000..1777031 --- /dev/null +++ b/pid_os/gpio.c @@ -0,0 +1,19 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "gpio.h" + +static volatile uint32_t* gpio_fsel = (uint32_t*) (GPIO_BASE); + +void gpio_set_func(unsigned pin, gpio_func_t fn) { + if (pin >= 32) + return; + unsigned off = (pin % 10) * 3; + unsigned idx = pin / 10; + + uint32_t v = gpio_fsel[idx]; + v &= ~(0b111 << off); + v |= fn << off; + gpio_fsel[idx] = v; +} diff --git a/pid_os/gpio.h b/pid_os/gpio.h new file mode 100644 index 0000000..d3dc3ab --- /dev/null +++ b/pid_os/gpio.h @@ -0,0 +1,75 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +enum { + GPIO_TX = 14, + GPIO_RX = 15, + GPIO_SDA = 2, + GPIO_SCL = 3, +}; + +typedef enum { + GPIO_FUNC_INPUT = 0, + GPIO_FUNC_OUTPUT = 1, + GPIO_FUNC_ALT0 = 4, + GPIO_FUNC_ALT1 = 5, + GPIO_FUNC_ALT2 = 6, + GPIO_FUNC_ALT3 = 7, + GPIO_FUNC_ALT4 = 3, + GPIO_FUNC_ALT5 = 2, +} gpio_func_t; + +#define GPIO_BASE 0xa0200000 + +static volatile uint32_t* gpio_set = (uint32_t*) (GPIO_BASE + 0x1C); +static volatile uint32_t* gpio_clr = (uint32_t*) (GPIO_BASE + 0x28); +static volatile uint32_t* gpio_lev = (uint32_t*) (GPIO_BASE + 0x34); + +void gpio_set_func(unsigned pin, gpio_func_t fn); +void gpio_set_output(unsigned pin); +void gpio_set_on(unsigned pin); +void gpio_set_off(unsigned pin); +void gpio_set_input(unsigned pin); +void gpio_write(unsigned pin, bool v); +bool gpio_read(unsigned pin); + +static inline void gpio_set_on_fast(unsigned pin) { + gpio_set[0] = 1 << pin; +} + +static inline void gpio_set_off_fast(unsigned pin) { + gpio_clr[0] = 1 << pin; +} + +static inline void gpio_write_fast(unsigned pin, bool v) { + if (v) { + gpio_set_on_fast(pin); + } else { + gpio_set_off_fast(pin); + } +} + +static inline bool gpio_read_fast(unsigned pin) { + return (gpio_lev[0] >> pin) & 1; +} + +void gpio_set_pullup(unsigned pin); +void gpio_set_pulldown(unsigned pin); +void gpio_pud_off(unsigned pin); + +enum { + GPIO_INT0 = 49, + GPIO_INT1, + GPIO_INT2, + GPIO_INT3, +}; + +int is_gpio_int(unsigned gpio_int); +void gpio_int_rise(unsigned pin); +void gpio_int_fall(unsigned pin); +void gpio_int_rise_async(unsigned pin); +void gpio_int_fall_async(unsigned pin); +int gpio_event_detect(unsigned pin); +void gpio_event_clear(unsigned pin); diff --git a/pid_os/memmap.ld b/pid_os/memmap.ld new file mode 100644 index 0000000..f24fd56 --- /dev/null +++ b/pid_os/memmap.ld @@ -0,0 +1,32 @@ +SECTIONS +{ + .text 0x8000 : { + __code_start__ = .; + KEEP(*(.boot)) + *(.text*) + __code_end__ = .; + . = ALIGN(8); + } + .rodata : { + __rodata_start__ = .; + *(.rodata*) + __rodata_end__ = .; + } + .data : { + __data_start__ = .; + *(.data*) + . = ALIGN(4); + __data_end__ = .; + } + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + __bss_end__ = .; + . = ALIGN(8); + __prog_end__ = .; + __heap_start__ = .; + } +} diff --git a/pid_os/pidos.c b/pid_os/pidos.c new file mode 100644 index 0000000..9ef6f31 --- /dev/null +++ b/pid_os/pidos.c @@ -0,0 +1,18 @@ +#include "uart.h" +#include "../kern/syscall_list.h" + +extern uint32_t syscall(uint32_t syscall, ...); + +unsigned main() { + init_printf(NULL, uart_putc); + + uint32_t pid = syscall(SYSCALL_GET_PID); + while (true) { + printf("Hello from process %lu\n", pid); + for (size_t i = 0; i < (1 << 21); i++) { + asm volatile ("nop"); + } + } + + return 24; +} diff --git a/pid_os/start.s b/pid_os/start.s new file mode 100644 index 0000000..fb86cff --- /dev/null +++ b/pid_os/start.s @@ -0,0 +1,34 @@ +#include "../kern/syscall_list.h" + +#define STACK_ADDR 0x8000000 + +.section ".boot" + +.globl _start +_start: + mov r0, #SYSCALL_ALLOC_PAGE + mov r1, #SYSCALL_ARG_ANY_PAGE + mov r2, #SIZE_1MB + swi 0 // result in r0 + + mov r1, #STACK_ADDR // virtual page + sub r1, r1, #SIZE_1MB // start of page for stack + mov r2, r0 // physical page + mov r3, #0 // flags + mov r4, #SIZE_1MB // size + mov r0, #SYSCALL_VM_MAP + swi 0 + + mov sp, #STACK_ADDR // Now we have a stack ! + sub sp, sp, #4 + + bl main + + mov r1, r0 + mov r0, #SYSCALL_EXIT + swi 0 + +.globl syscall +syscall: + swi 0 + bx lr diff --git a/pid_os/uart.c b/pid_os/uart.c new file mode 100644 index 0000000..f69a791 --- /dev/null +++ b/pid_os/uart.c @@ -0,0 +1,105 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "dev.h" +#include "gpio.h" +#include "uart.h" + +typedef struct { + uint32_t io; + uint32_t ier; + uint32_t iir; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +} aux_periphs_t; + +#define ENABLE_UART 1 +#define RX_ENABLE (1 << 0) +#define TX_ENABLE (1 << 1) +#define CLEAR_TX_FIFO (1 << 1) +#define CLEAR_RX_FIFO (1 << 2) +#define CLEAR_FIFOS (CLEAR_TX_FIFO | CLEAR_RX_FIFO) +#define IIR_RESET ((0b11 << 6) | 1) + +// TODO: should eventually ask the kernel for access instead of using its pages +// (eventually these will be write protected) +#define pa2ka(pa) ((pa | (1 << 31))) +#define ka2pa(ka) ((ka & ~(1 << 31))) +static volatile uint32_t* const aux_enables = (uint32_t*) pa2ka(0x20215004); +static volatile aux_periphs_t* const uart = (aux_periphs_t*) pa2ka(0x20215040); + +void uart_init(unsigned baud) { + gpio_set_func(GPIO_TX, GPIO_FUNC_ALT5); + gpio_set_func(GPIO_RX, GPIO_FUNC_ALT5); + + dev_barrier(); + + *aux_enables = *aux_enables | ENABLE_UART; + + dev_barrier(); + + uart->cntl = 0; + uart->ier = 0; + uart->lcr = 0b11; + uart->mcr = 0; + uart->iir = IIR_RESET | CLEAR_FIFOS; + uart->baud = (250 * 1000 * 1000) / (baud * 8) - 1; + uart->cntl = RX_ENABLE | TX_ENABLE; + + dev_barrier(); +} + +bool uart_rx_empty() { + return bit_get(uart->stat, 0) == 0; +} + +unsigned uart_rx_sz() { + return bits_get(uart->stat, 16, 19); +} + +bool uart_can_tx() { + return bit_get(uart->stat, 1) != 0; +} + +uint8_t uart_rx() { + dev_barrier(); + while (uart_rx_empty()) + ; + uint8_t c = uart->io & 0xff; + dev_barrier(); + return c; +} + +void uart_tx(uint8_t c) { + dev_barrier(); + while (!uart_can_tx()) + ; + uart->io = c & 0xff; + dev_barrier(); +} + +void uart_putc(void* p, char c) { + (void) p; + uart_tx(c); +} + +bool uart_tx_empty() { + dev_barrier(); + + // broadcom p 18: "This bit (9) is set if the transmitter is idle and the + // transmit FIFO is empty." + // transmitter done: idle and empty + return bit_get(uart->stat, 9) == 1; +} + +void uart_tx_flush() { + while (!uart_tx_empty()) + ; +} diff --git a/pid_os/uart.h b/pid_os/uart.h new file mode 100644 index 0000000..e7b655f --- /dev/null +++ b/pid_os/uart.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "../libc/tinyprintf.h" + +void uart_init(unsigned baud); +bool uart_rx_empty(); +bool uart_can_tx(); +unsigned uart_rx_sz(); +uint8_t uart_rx(); +void uart_tx(uint8_t c); +bool uart_tx_empty(); +void uart_tx_flush(); + +// for tinyprintf +void uart_putc(void* p, char c); @@ -1,38 +0,0 @@ -#pragma once - -#include "bits.h" -#include "gpio.h" -#include "i2c.h" -#include "interrupts.h" -#include "kmalloc.h" -#include "ksan.h" -#include "libc/tinyprintf.h" -#include "timer.h" -#include "uart.h" -#include "vm.h" - -void kernel_start(); -void reboot(); - -static inline void cache_enable(void) { - unsigned r; - asm volatile("MRC p15, 0, %0, c1, c0, 0" : "=r"(r)); - r |= (1 << 12); // l1 instruction cache - r |= (1 << 11); // branch prediction - asm volatile("MCR p15, 0, %0, c1, c0, 0" ::"r"(r)); -} - -static inline void cache_disable(void) { - unsigned r; - asm volatile("MRC p15, 0, %0, c1, c0, 0" : "=r"(r)); - r &= ~(1 << 12); // l1 instruction cache - r &= ~(1 << 11); // branch prediction - asm volatile("MCR p15, 0, %0, c1, c0, 0" ::"r"(r)); -} - -#define panic(format, args...) \ - do { \ - printf("PANIC: "); \ - printf(format, ##args); \ - reboot(); \ - } while (0) diff --git a/pios.mk b/pios.mk deleted file mode 100644 index 0141b34..0000000 --- a/pios.mk +++ /dev/null @@ -1,8 +0,0 @@ -MEMMAP = $(PIOS)/memmap.ld - -PIOS_CSRC = $(wildcard $(PIOS)/*.c) $(wildcard $(PIOS)/libc/*.c) -PIOS_HSRC = $(wildcard $(PIOS)/*.h) $(wildcard $(PIOS)/libc/*.h) -PIOS_SSRC = $(wildcard $(PIOS)/*.s) - -PIOS_OBJ_NOSAN = $(PIOS)/uart.o $(PIOS)/ksan.o $(PIOS)/cstart.o $(PIOS)/start.o $(PIOS)/gpio.o $(PIOS)/kmalloc.o $(PIOS)/libc/tinyprintf.o -PIOS_OBJ = $(PIOS_CSRC:.c=.o) $(PIOS_SSRC:.s=.o) diff --git a/plugin/memtrace/Makefile b/plugin/memtrace/Makefile deleted file mode 100644 index 2d990bb..0000000 --- a/plugin/memtrace/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -CC = gcc - -all: libmemtrace.so - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< - -lib%.so: %.o - $(CC) -shared -Wl,-soname,$@ -o $@ $< diff --git a/plugin/memtrace/memtrace.c b/plugin/memtrace/memtrace.c deleted file mode 100644 index 8631beb..0000000 --- a/plugin/memtrace/memtrace.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2021, Alexandre Iooss <erdnaxe@crans.org> - * - * Log instruction execution with memory access. - * - * License: GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ -#include <glib.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <qemu-plugin.h> - -QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; - -/** - * Add memory read or write information to current instruction log - */ -static void vcpu_mem(unsigned int cpu_index, qemu_plugin_meminfo_t info, - uint64_t vaddr, void *udata) -{ - GString* s = g_string_new(NULL); - - /* uint64_t insn_vaddr = qemu_plugin_insn_vaddr(insn); */ - /* g_string_append_printf(s, "%lx: ", insn_vaddr); */ - - if (qemu_plugin_mem_is_store(info)) { - g_string_append(s, "st: "); - } else { - g_string_append(s, "ld: "); - } - - /* If full system emulation log physical address and device name */ - struct qemu_plugin_hwaddr *hwaddr = qemu_plugin_get_hwaddr(info, vaddr); - if (hwaddr) { - uint64_t addr = qemu_plugin_hwaddr_phys_addr(hwaddr); - const char *name = qemu_plugin_hwaddr_device_name(hwaddr); - g_string_append_printf(s, "0x%08"PRIx64" (%s)", addr, name); - } else { - g_string_append_printf(s, "0x%08"PRIx64" (vaddr)", vaddr); - } - - g_string_append(s, "\n"); - - qemu_plugin_outs(s->str); -} - -/** - * On translation block new translation - * - * QEMU convert code by translation block (TB). By hooking here we can then hook - * a callback on each instruction and memory access. - */ -static void vcpu_tb_trans(qemu_plugin_id_t id, struct qemu_plugin_tb *tb) -{ - struct qemu_plugin_insn *insn; - uint64_t insn_vaddr; - uint32_t insn_opcode; - char *insn_disas; - - size_t n = qemu_plugin_tb_n_insns(tb); - for (size_t i = 0; i < n; i++) { - insn = qemu_plugin_tb_get_insn(tb, i); - /* Register callback on memory read or write */ - qemu_plugin_register_vcpu_mem_cb(insn, vcpu_mem, - QEMU_PLUGIN_CB_NO_REGS, - QEMU_PLUGIN_MEM_RW, NULL); - } -} - -/** - * Install the plugin - */ -QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id, - const qemu_info_t *info, int argc, - char **argv) -{ - /* Register translation block and exit callbacks */ - qemu_plugin_register_vcpu_tb_trans_cb(id, vcpu_tb_trans); - - return 0; -} - diff --git a/prog/ads1115/Makefile b/prog/ads1115/Makefile deleted file mode 100644 index 663ca94..0000000 --- a/prog/ads1115/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = main - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/ads1115/ads1115.c b/prog/ads1115/ads1115.c deleted file mode 100644 index 266368f..0000000 --- a/prog/ads1115/ads1115.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "pios.h" -#include "ads1115.h" - -void ads1115_reset() { - uint8_t rst = 0x6; - i2c_write(0, &rst, 1); -} - -void ads1115_write(uint8_t dev_addr, uint8_t reg, uint16_t v) { - uint8_t data[3] = {reg, v >> 8, v & 0xff}; - i2c_write(dev_addr, data, 3); -} - -uint16_t ads1115_read(uint8_t dev_addr, uint8_t reg) { - i2c_write(dev_addr, ®, 1); - uint8_t data[2]; - i2c_read(dev_addr, data, 2); - return ((uint16_t) data[0] << 8) | data[1]; -} - -uint8_t ads1115_config() { - uint8_t dev_addr = 0b1001000; - - ads1115_reset(); - delay_us(25); - - uint16_t c = ads1115_read(dev_addr, config_reg); - c = bits_set(c, 8, 8, 0); // MODE - c = bits_set(c, 5, 7, 0b111); // DR - c = bits_set(c, 9, 11, 0b001); // PGA - c = bits_set(c, 12, 14, 0b100); // MUX - ads1115_write(dev_addr, config_reg, c); - - return dev_addr; -} diff --git a/prog/ads1115/ads1115.h b/prog/ads1115/ads1115.h deleted file mode 100644 index c0e74c9..0000000 --- a/prog/ads1115/ads1115.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include <stdint.h> - -enum { - conversion_reg = 0, - config_reg = 1, -}; - -void ads1115_reset(); -void ads1115_write(uint8_t dev_addr, uint8_t reg, uint16_t v); -uint16_t ads1115_read(uint8_t dev_addr, uint8_t reg); -uint8_t ads1115_config(); diff --git a/prog/ads1115/main.c b/prog/ads1115/main.c deleted file mode 100644 index 6cbfa7c..0000000 --- a/prog/ads1115/main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "pios.h" -#include "ads1115.h" - -int main() { - i2c_init(); - - uint8_t dev_addr = ads1115_config(); - - for (unsigned i = 0; i < 50; i++) { - int16_t v = ads1115_read(dev_addr, conversion_reg); - printf("read=%d\n", v); - delay_ms(250); - } - - return 0; -} diff --git a/prog/analyzer/Makefile b/prog/analyzer/Makefile deleted file mode 100644 index 52d5d6a..0000000 --- a/prog/analyzer/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = analyzer - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -qemu: $(PROG).elf - qemu-system-arm -M raspi1ap -plugin $(PIOS)/plugin/memtrace/libmemtrace.so -nographic -d plugin -D trace.txt -kernel $< -serial null -serial mon:stdio -no-reboot - -.PHONY: format clean all install qemu diff --git a/prog/analyzer/analyzer.c b/prog/analyzer/analyzer.c deleted file mode 100644 index 24df286..0000000 --- a/prog/analyzer/analyzer.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "pios.h" - -#include <string.h> - -#define PIN 21 - -typedef struct { - unsigned ncycles; - unsigned v; -} event_t; - -unsigned analyze(event_t* events, size_t N) { - unsigned n = 0; - while (n < N) { - unsigned v1, v0 = gpio_read_fast(PIN); - while ((v1 = gpio_read_fast(PIN)) == v0) {} - unsigned time = timer_cycles(); - events[n] = (event_t){ - .ncycles = time, - .v = v1, - }; - n++; - v0 = v1; - } - return n; -} - -#define N 11 - -static int abs(int i) { - if (i < 0) { - return -i; - } - return i; -} - -static unsigned ns_to_cyc(unsigned ns) { - return ns * CPU_FREQ_MHZ / 1000; -} - -static unsigned cyc_to_ns(unsigned cyc) { - return cyc * 1000 / CPU_FREQ_MHZ; -} - -int main() { - gpio_set_input(PIN); - event_t events[N]; - - while (1) { - unsigned n = analyze(events, N); - unsigned start = events[0].ncycles; - for (int i = 0; i < n; i++) { - unsigned got = cyc_to_ns(events[i].ncycles - start); - printf("pin-%d: %d %d\n", PIN, got, events[i].v); - } - delay_ms(100); - memset(events, 0, sizeof(event_t) * N); - } - - return 0; -} - -int test() { - gpio_set_input(PIN); - event_t events[N]; - - printf("Waiting for change on pin %d\n", PIN); - - for (int l = 0; l < 4; l++) { - unsigned n = analyze(events, N); - - printf("%d results\n", n); - - unsigned start = events[0].ncycles; - int toterr = 0; - for (int i = 0; i < n; i++) { - unsigned got = cyc_to_ns(events[i].ncycles - start); - unsigned want = i * 6000 * 1000 / 700; - int err = abs((int) (want - got)); - toterr += err; - printf("%d: got: %d ns, (err %d ns, toterr %d ns) (%d pi cycles)\n", events[i].v, got, err, toterr, ns_to_cyc(got)); - } - - printf("toterr: %d pi cycles\n", ns_to_cyc(toterr)); - - delay_ms(100); - - memset(events, 0, sizeof(event_t) * N); - } - - return 0; -} diff --git a/prog/basic/Makefile b/prog/basic/Makefile new file mode 100644 index 0000000..c33b3e7 --- /dev/null +++ b/prog/basic/Makefile @@ -0,0 +1,14 @@ +include ../../defs.mk + +PROG = basic +MEMMAP = $(PROG).ld + +exostall: $(PIOS)/kern/p-$(PROG).o + +$(PROG).elf: $(MEMMAP) $(PROG).o + $(LD) $(LDFLAGS) $(filter-out $<,$^) $(LDLIBS) -o $@ + +$(PIOS)/kern/p-$(PROG).o: $(PROG).bin + $(LD) -r -b binary -o $@ $< + +.PHONY: exostall diff --git a/prog/basic/basic.ld b/prog/basic/basic.ld new file mode 100644 index 0000000..9762c82 --- /dev/null +++ b/prog/basic/basic.ld @@ -0,0 +1,20 @@ +SECTIONS +{ + .text 0x8000 : { + KEEP(*(.text.boot)) + *(.text*) + . = ALIGN(8); + } + .rodata : { *(.rodata*) } + .data : { + *(.data*) + . = ALIGN(4); + } + .bss : { + . = ALIGN(4); + *(.bss*) + *(COMMON) + . = ALIGN(8); + . = ALIGN(8); + } +} diff --git a/prog/basic/basic.s b/prog/basic/basic.s new file mode 100644 index 0000000..513b22e --- /dev/null +++ b/prog/basic/basic.s @@ -0,0 +1,6 @@ +.section ".text.boot" + +.globl start +_start: + mov r0, #0 + swi 0 diff --git a/prog/gpio_int/Makefile b/prog/gpio_int/Makefile deleted file mode 100644 index 91a5d7d..0000000 --- a/prog/gpio_int/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = gpio_int - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/gpio_int/gpio_int.c b/prog/gpio_int/gpio_int.c deleted file mode 100644 index c585113..0000000 --- a/prog/gpio_int/gpio_int.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "pios.h" -#include "dev.h" - -void __attribute__((interrupt("IRQ"))) irq() { - dev_barrier(); - - if (!irq_pending(GPIO_INT3)) { - return; - } - printf("irq %d\n", gpio_event_detect(21)); - gpio_event_clear(21); - - dev_barrier(); -} - -int main() { - gpio_set_input(21); - gpio_set_output(20); - - irq_init_table(); - gpio_int_rise(21); - gpio_int_fall(21); - register_irq_vec(IRQ_VEC_IRQ, (uintptr_t) irq); - enable_interrupts(); - - gpio_write(20, 1); - delay_ms(1000); - gpio_write(20, 0); - delay_ms(1000); - return 0; -} diff --git a/prog/hello/Makefile b/prog/hello/Makefile deleted file mode 100644 index 4ec123e..0000000 --- a/prog/hello/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = hello - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/hello/hello.c b/prog/hello/hello.c deleted file mode 100644 index afe7cbc..0000000 --- a/prog/hello/hello.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "pios.h" - -int main() { - printf("Hello world\n"); - return 0; -} diff --git a/prog/irq/Makefile b/prog/irq/Makefile deleted file mode 100644 index 634a389..0000000 --- a/prog/irq/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = irq - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/irq/irq.c b/prog/irq/irq.c deleted file mode 100644 index 8d59e62..0000000 --- a/prog/irq/irq.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "pios.h" -#include "dev.h" - -static bool v = true; -void __attribute((interrupt("IRQ"))) irq() { - dev_barrier(); - - if (!timer_has_irq()) { - return; - } - - gpio_write(21, v); - v = !v; - - dev_barrier(); - - timer_clear_irq(); - - dev_barrier(); -} - -int main() { - gpio_set_output(21); - - irq_init_table(); - irq_enable(BASIC_TIMER_IRQ); - timer_irq_load(0x400); - register_irq_vec(IRQ_VEC_IRQ, (uintptr_t) irq); - - enable_interrupts(); - - delay_ms(3000); - return 0; -} diff --git a/prog/mmu/Makefile b/prog/mmu/Makefile deleted file mode 100644 index d1b109a..0000000 --- a/prog/mmu/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = mmu - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -clean: - rm -f *.list *.o $(PROG).elf $(PROG).bin - -format: - clang-format -i $(CSRC) $(HSRC) - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/mmu/mmu.c b/prog/mmu/mmu.c deleted file mode 100644 index 4e378ee..0000000 --- a/prog/mmu/mmu.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "pios.h" - -#define STACK_ADDR 0x8000000 -#define INT_STACK_ADDR 0x9000000 -#define CODE_ADDR 0x8000 - -int main() { - irq_init_table(); - enable_interrupts(); - - const int page_size = 4096; - - vm_init(); - - vm_map(0, 0, 0); - - for (unsigned i = 0; i < 4; i++) { - vm_map(STACK_ADDR - page_size * (i + 1), - STACK_ADDR - page_size * (i + 1), 0); - vm_map(INT_STACK_ADDR - page_size * (i + 1), - INT_STACK_ADDR - page_size * (i + 1), 0); - vm_map(CODE_ADDR + page_size * i, CODE_ADDR + page_size * i, 0); - } - - extern char __heap_start__; - for (unsigned i = 0; i < 512; i++) { - vm_map((uintptr_t) &__heap_start__ + page_size * i, - (uintptr_t) &__heap_start__ + page_size * i, 0); - vm_map(0x20000000 + page_size * i, 0x20000000 + page_size * i, 0); - vm_map(0x20200000 + page_size * i, 0x20200000 + page_size * i, 0); - } - - vm_enable(); - - printf("done!\n"); - - return 0; -} diff --git a/prog/mmu_realtime/Makefile b/prog/mmu_realtime/Makefile deleted file mode 100644 index 6b70ebe..0000000 --- a/prog/mmu_realtime/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = mmu_realtime - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) -SSRC = $(wildcard *.s) - -OBJ = $(SSRC:.s=.o) $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -clean: - rm -f *.list *.o $(PROG).elf $(PROG).bin - -format: - clang-format -i $(CSRC) $(SSRC) $(HSRC) - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/mmu_realtime/irq.s b/prog/mmu_realtime/irq.s deleted file mode 100644 index 59be40f..0000000 --- a/prog/mmu_realtime/irq.s +++ /dev/null @@ -1,17 +0,0 @@ -#define INT_STACK_ADDR 0x9000000 - -.globl irq_vec_asm -irq_vec_asm: - mov sp, #INT_STACK_ADDR - sub lr, lr, #4 // Update the lr to where we should jump back to - - push {lr} - stmfd sp, {r0-r14}^ - sub sp, sp, #60 - mov r0, sp - - bl irq // call our actual irq handler - - ldm sp, {r0-r15}^ // restore all registers, jump back. - // including r15 also tells ldm to restore spsr - // into cpsr diff --git a/prog/mmu_realtime/mmu_realtime.c b/prog/mmu_realtime/mmu_realtime.c deleted file mode 100644 index 7565b57..0000000 --- a/prog/mmu_realtime/mmu_realtime.c +++ /dev/null @@ -1,72 +0,0 @@ -#include "pios.h" - -#define STACK_ADDR 0x8000000 -#define INT_STACK_ADDR 0x9000000 -#define CODE_ADDR 0x8000 - -#define dsb() asm volatile("mcr p15, #0, %0, c7, c10, #4" : : "r"(0)) -static void system_invalidate_tlb(void) { - asm volatile("mcr p15, 0, %0, c8, c7, 0" : : "r"(0)); - dsb(); -} - -static void system_invalidate_cache(void) { - // See Fig 3.38 in section 3.2.22 in arm1176 - asm volatile("mcr p15, 0, %0, c7, c7, 0" : : "r"(0)); -} - -void irq(uint32_t *regs) { - regs[15] -= 4; // pc points to the _next_ instruction in irq - - unsigned addr = get_dfar(); - unsigned page = addr & (~(4096 - 1)); - printf("Data abort at PC 0x%x\n", regs[15]); - printf("\tInstruction: 0x%x\n", *(unsigned*)regs[15]); - printf("\tAddress: 0x%x\n", addr); - printf("\tAdding page: 0x%x to page table...\n", page); - vm_map(page, page, 0); - system_invalidate_tlb(); - system_invalidate_cache(); -} - -extern void irq_vec_asm(); -int main() { - irq_init_table(); - register_irq_vec(IRQ_VEC_DATA_ABORT, (uintptr_t)irq_vec_asm); - register_irq_vec(IRQ_VEC_PREFETCH_ABORT, (uintptr_t)irq_vec_asm); - enable_interrupts(); - - const int page_size = 4096; - - vm_init(); - - vm_map(0, 0, 0); - - for (unsigned i = 0; i < 4; i++) { - vm_map(STACK_ADDR - page_size * (i + 1), - STACK_ADDR - page_size * (i + 1), 0); - vm_map(INT_STACK_ADDR - page_size * (i + 1), - INT_STACK_ADDR - page_size * (i + 1), 0); - vm_map(CODE_ADDR + page_size * i, CODE_ADDR + page_size * i, 0); - } - - extern char __heap_start__; - for (unsigned i = 0; i < 512; i++) { - vm_map((uintptr_t) &__heap_start__ + page_size * i, - (uintptr_t) &__heap_start__ + page_size * i, 0); - vm_map(0x20000000 + page_size * i, 0x20000000 + page_size * i, 0); - vm_map(0x20200000 + page_size * i, 0x20200000 + page_size * i, 0); - } - - vm_enable(); - - printf("done!\n"); - - volatile unsigned *ptr = (void*)0x30200005; - *ptr = 5; - printf("Wrote data: %u\n", *ptr); - *ptr = 10; - printf("Overwrote data: %u\n", *ptr); - - return 0; -} diff --git a/prog/san/Makefile b/prog/san/Makefile deleted file mode 100644 index 694b0bf..0000000 --- a/prog/san/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -SANITIZE = 1 - -include ../../pios.mk -include ../../defs.mk - -O ?= s -TEST ?= 1 -TESTS = 1 2 3 4 5 6 -PROGS = $(addprefix test-,$(TESTS)) - -SRC = san.c - -CFLAGS += -I$(PIOS) - -all: $(addsuffix .bin,$(PROGS)) $(addsuffix .elf,$(PROGS)) - -install: test-$(TEST).bin - pi-install $< - -san-%.o: $(SRC) - $(CC) $(CFLAGS) -DTEST=$* $(ASAN_FLAGS) $< -c -o $@ - -test-%.elf: $(PIOS_OBJ) san-%.o - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -clean: - rm -f *.list *.o *.elf *.bin - -format: - clang-format -i $(SRC) - -qemu: test-$(TEST).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -.PHONY: format clean all install - diff --git a/prog/san/san.c b/prog/san/san.c deleted file mode 100644 index 63c6464..0000000 --- a/prog/san/san.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "pios.h" - -void unreachable() { - printf("should panic due to unreachable\n"); - - __builtin_unreachable(); // should panic -} - -static volatile int g; -void overflow() { - printf("should panic due to integer overflow\n"); - - int s = 2; - for (int i = 0; i < 100; i++) { - s = s * s; // should panic - } - // use result to prevent optimization - g = s; -} - -void use_after_free() { - printf("should panic in heap\n"); - - int* p = (int*) kmalloc(sizeof(int)); - *p = 42; - kfree(p); - g = *p; // should panic -} - -void illegal_access() { - printf("should panic in heap\n"); - - int* p = (int*) kmalloc(sizeof(int) * 4); - memset(p, 0, 4); - g = p[4]; // should panic - kfree(p); -} - -void legal_access() { - printf("should not panic\n"); - - int* p = (int*) kmalloc(sizeof(int) * 4); - memset(p, 0, 4); - g = p[3]; // should not panic - kfree(p); -} - -void invalid_code() { - printf("should panic on code segment\n"); - - memset(invalid_code, 0, 8); // should panic -} - -int main() { -#if (TEST == 1) - unreachable(); -#elif (TEST == 2) - use_after_free(); -#elif (TEST == 3) - invalid_code(); -#elif (TEST == 4) - illegal_access(); -#elif (TEST == 5) - legal_access(); -#elif (TEST == 6) - overflow(); -#endif - - return 0; -} diff --git a/prog/threads/Makefile b/prog/threads/Makefile deleted file mode 100644 index 3b79542..0000000 --- a/prog/threads/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = threads - -CSRC = $(wildcard *.c) -SSRC = $(wildcard *.s) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(SSRC:.s=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -clean: - rm -f *.list *.o $(PROG).elf $(PROG).bin - -format: - clang-format -i $(CSRC) $(HSRC) - -qemu: $(PROG).elf - $(QEMU) -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot - -qemu-gdb: $(PROG).elf - $(QEMU) -s -S -M $(BOARD) -nographic -kernel $< -serial null -serial mon:stdio -no-reboot & - $(GDB) -ex "file $(PROG).elf" -ex "target remote localhost:1234" - -.PHONY: format clean all install qemu diff --git a/prog/threads/irq_asm.s b/prog/threads/irq_asm.s deleted file mode 100644 index 87cb8ae..0000000 --- a/prog/threads/irq_asm.s +++ /dev/null @@ -1,18 +0,0 @@ -#define INT_STACK_ADDR 0x9000000 - -.globl irq_vec_asm -// TODO: Need to also save cpsr, maybe other state ? -irq_vec_asm: - mov sp, #INT_STACK_ADDR - sub lr, lr, #4 // Update the lr to where we should jump back to - - push {lr} - stmfd sp, {r0-r14}^ - sub sp, sp, #60 - mov r0, sp - - bl irq // call our actual irq handler - - ldm sp, {r0-r15}^ // restore all registers, jump back. - // including r15 also tells ldm to restore spsr - // into cpsr diff --git a/prog/threads/threads.c b/prog/threads/threads.c deleted file mode 100644 index c7c9100..0000000 --- a/prog/threads/threads.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "pios.h" -#include "dev.h" - -extern void irq_vec_asm(); - -struct thread { - volatile uint32_t registers[16]; -}; - -volatile struct thread threads[100]; -volatile unsigned n_threads = 1; -volatile unsigned curr_thread_id = 0; - -void swippityswap(volatile uint32_t *live_state, volatile struct thread *new_thread, volatile struct thread *old_thread) { - for (size_t i = 0; i < 16; i++) { - old_thread->registers[i] = live_state[i]; - live_state[i] = new_thread->registers[i]; - } -} - -void irq(uint32_t *state_ptr) { - dev_barrier(); - if (!timer_has_irq()) return; - - unsigned next_thread_id = (curr_thread_id + 1) % n_threads; - if (next_thread_id == curr_thread_id) goto end; - - swippityswap(state_ptr, &(threads[next_thread_id]), &(threads[curr_thread_id])); - curr_thread_id = next_thread_id; - -end: - dev_barrier(); - timer_clear_irq(); - dev_barrier(); -} - -void spawn(void (*foo)(unsigned), unsigned arg) { - uint32_t *stack = kmalloc(1024 * 1024 * 4); - unsigned thread_id = n_threads++; - - for (size_t i = 0; i < 16; i++) - threads[thread_id].registers[i] = 0; - - threads[thread_id].registers[0] = arg; - threads[thread_id].registers[13] = (uint32_t)stack; - threads[thread_id].registers[15] = (uint32_t)foo; -} - -void worker(unsigned which) { - bool lit = false; - while (true) { - gpio_write(which, lit); - lit = !lit; - printf("Hello from worker on gpio %u\n", which); - delay_ms(1000); - } -} - -int main() { - gpio_set_output(21); - gpio_set_output(20); - - irq_init_table(); - irq_enable(BASIC_TIMER_IRQ); - timer_irq_load(0x1000); - register_irq_vec(IRQ_VEC_IRQ, (uintptr_t) irq_vec_asm); - - enable_interrupts(); - - spawn(worker, 21); - spawn(worker, 20); - - while (true); - - return 0; -} diff --git a/prog/ws2812b/Makefile b/prog/ws2812b/Makefile deleted file mode 100644 index d066764..0000000 --- a/prog/ws2812b/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -include ../../pios.mk -include ../../defs.mk - -O ?= s - -PROG = lights - -CSRC = $(wildcard *.c) -HSRC = $(wildcard *.h) - -OBJ = $(CSRC:.c=.o) $(PIOS_OBJ) - -CFLAGS += -I$(PIOS) - -all: $(PROG).bin - -install: $(PROG).bin - pi-install $< - -$(PROG).elf: $(OBJ) - $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -include ../../common.mk - -.PHONY: format clean all install diff --git a/prog/ws2812b/lights.c b/prog/ws2812b/lights.c deleted file mode 100644 index 7fae61f..0000000 --- a/prog/ws2812b/lights.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "pios.h" -#include "lights.h" - -void two_lights(unsigned lights_pin) { - unsigned npix = 30; - unsigned iter = 0; - - uint8_t r1, g1, b1; - uint8_t r2, g2, b2; - r1 = g1 = b1 = 0; - r2 = g2 = b2 = 0; - - while (1) { - for (int i = 0; i < npix; i++) { - unsigned led1 = iter % 2 == 0 ? i : npix - i - 1; - unsigned led2 = iter % 2 == 0 ? npix - i - 1 : i; - - for (int p = 0; p < npix; p++) { - if (p == led1) { - write_rgb(lights_pin, r1, g1, b1); - } else if (p == led2) { - write_rgb(lights_pin, r2, g2, b2); - } else { - write_rgb(lights_pin, 0, 0, 0); - } - } - flush(lights_pin); - delay_ms(20); - - r1 = iter % 2 == 0 ? 8*i : 255 - 8*i; - g1 = iter % 2 == 0 ? 255 - 8*i : 8*i; - b1 = 0; - - r2 = 0; - g2 = iter % 2 == 0 ? 8*i : 255 - 8*i; - b2 = iter % 2 == 0 ? 255 - 8*i : 8*i; - } - iter++; - } -} - -int main() { - unsigned pin = 21; - gpio_set_output(pin); - two_lights(pin); - return 0; -} diff --git a/prog/ws2812b/lights.h b/prog/ws2812b/lights.h deleted file mode 100644 index 64ddf27..0000000 --- a/prog/ws2812b/lights.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include "pios.h" - -#define ns_to_cycles(x) (unsigned) ((x * CPU_FREQ_MHZ) / 1000) - -const int compensation = 16; - -static inline void write_0(unsigned pin) { - unsigned start = timer_cycles(); - gpio_write_fast(pin, 1); - start = delay_ncycles(start, ns_to_cycles(350)-compensation); - gpio_write_fast(pin, 0); - delay_ncycles(start, ns_to_cycles(900)-compensation); -} - -static inline void write_1(unsigned pin) { - unsigned start = timer_cycles(); - gpio_write_fast(pin, 1); - start = delay_ncycles(start, ns_to_cycles(900)-compensation); - gpio_write_fast(pin, 0); - delay_ncycles(start, ns_to_cycles(350)-compensation); -} - -static inline void flush(unsigned pin) { - gpio_write(pin, 0); - delay_us(50); -} - -static inline void write_bit(unsigned pin, uint8_t bit) { - if (bit) { - write_1(pin); - } else { - write_0(pin); - } -} - -static inline void write_byte(unsigned pin, uint8_t byte) { - // big-endian - for (int i = 7; i >= 0; i--) { - write_bit(pin, (byte >> i) & 0x1); - } -} - -static inline void write_rgb(unsigned pin, uint8_t r, uint8_t g, uint8_t b) { - write_byte(pin, g); - write_byte(pin, r); - write_byte(pin, b); -} diff --git a/start.s b/start.s deleted file mode 100644 index 2175b1d..0000000 --- a/start.s +++ /dev/null @@ -1,19 +0,0 @@ -#include "asm.h" - -.section ".boot" - -.globl _start -_start: - # force the mode to be system - mov r0, #SYS_MODE - # disable interrupts - orr r0, r0, #(1 << 7) - msr cpsr, r0 - prefetch_flush(r1) - - mov sp, #STACK_ADDR - # clear frame pointer - mov fp, #0 - bl cstart -_hlt: - b _hlt @@ -6,3 +6,7 @@ riscv/portable gpu https://www.valvers.com/open-software/raspberry-pi/bare-metal-programming-in-c-part-4/ + +exo: +- asan +- user mode diff --git a/tools/exify/exify.sh b/tools/exify/exify.sh new file mode 100755 index 0000000..bc10985 --- /dev/null +++ b/tools/exify/exify.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +echo "#include <string.h>" +echo "unsigned char prog_$2[] = {" +hexdump -v -e '"\t" 4/1 "0x%02x, " "\n"' $1 +echo "};" +echo "size_t prog_$2_sz = sizeof(prog_$2);" @@ -1,46 +0,0 @@ -#include "vm.h" -#include "pios.h" - -static pde_t* pgdir; - -void vm_init() { - pgdir = kmalloc_aligned(4096 * sizeof(pde_t), 1 << 14); - memset(pgdir, 0, 4096 * sizeof(pde_t)); -} - -static void init_second_level(pde_t* pde) { - pte_small_t* pgtbl = kmalloc_aligned(256 * sizeof(pte_small_t), 1 << 10); - memset(pgtbl, 0, 256 * sizeof(pte_small_t)); - pde->addr = (uintptr_t) pgtbl >> 10; - pde->tag = 0b01; -} - -void vm_map(uintptr_t va, uintptr_t pa, unsigned flags) { - unsigned pde_idx = va >> 20; - pde_t* pde = &pgdir[pde_idx]; - - switch (pde->tag) { - case 0b00: - init_second_level(pde); - case 0b01:; - pte_small_t* pgtbl = (pte_small_t*) (pde->addr << 10); - pte_small_t* pte = &pgtbl[bits_get(va, 12, 19)]; - pte->addr = pa >> 12; - pte->ap = AP_RW; - pte->sz = 1; - break; - default: - panic("invalid pde tag: %d\n", pde->tag); - } -} - -void vm_enable() { - sys_invalidate_cache(); - sys_invalidate_tlb(); - dsb(); - sys_set_domain(DOM_CLIENT); - sys_set_tlb_base((uintptr_t) pgdir); - sys_set_cache_control(SYS_MMU_ENABLE | SYS_DCACHE_ENABLE | - SYS_ICACHE_ENABLE | SYS_BRANCH_PREDICTION_ENABLE | - SYS_WRITE_BUFFER_ENABLE | SYS_MMU_XP); -} |