summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZachary Yedidia <zyedidia@gmail.com>2022-05-19 17:14:28 -0700
committerZachary Yedidia <zyedidia@gmail.com>2022-05-19 17:14:28 -0700
commita950066d8a800e78445d8b2b89e2cfa03bd808e1 (patch)
tree380c0194b14f4fd24a00c0dea102eac6a2eccc04
parent0b82ab2c9732d69f141361c659c7773fd4e6a38a (diff)
parentf746a5d6fc1b1ec0044d1bd86d1ed2020837e9ec (diff)
Merge branch 'exo'
-rw-r--r--.clang-format2
-rw-r--r--.editorconfig2
-rw-r--r--.gitignore2
-rw-r--r--INSTALL.md8
-rw-r--r--cstart.c39
-rw-r--r--defs.mk12
-rw-r--r--hello_os/Makefile32
-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.c19
-rw-r--r--hello_os/gpio.h (renamed from gpio.h)0
-rw-r--r--hello_os/hello.c27
-rw-r--r--hello_os/memmap.ld (renamed from memmap.ld)0
-rw-r--r--hello_os/start.s34
-rw-r--r--hello_os/uart.c105
-rw-r--r--hello_os/uart.h (renamed from uart.h)2
-rw-r--r--i2c.c155
-rw-r--r--i2c.h7
-rw-r--r--interrupts-asm.s67
-rw-r--r--kern.c13
-rw-r--r--kern/Makefile64
-rw-r--r--kern/asm.h (renamed from asm.h)7
-rw-r--r--kern/bits.h78
-rw-r--r--kern/boot.c89
-rw-r--r--kern/dev.h5
-rw-r--r--kern/gpio.c (renamed from gpio.c)16
-rw-r--r--kern/gpio.h77
-rw-r--r--kern/interrupts-asm.s81
-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.c81
-rw-r--r--kern/kern.h29
-rw-r--r--kern/kern.mk10
-rw-r--r--kern/kmalloc.c239
-rw-r--r--kern/kmalloc.h18
-rw-r--r--kern/ksan.c228
-rw-r--r--kern/ksan.h6
-rw-r--r--kern/lib.h5
-rw-r--r--kern/memmap.ld55
-rw-r--r--kern/proc.c70
-rw-r--r--kern/proc.h51
-rw-r--r--kern/start.s29
-rw-r--r--kern/sys.h (renamed from sys.h)48
-rw-r--r--kern/syscall.c61
-rw-r--r--kern/syscall_list.h14
-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.h61
-rw-r--r--kern/uart.c (renamed from uart.c)6
-rw-r--r--kern/uart.h18
-rw-r--r--kern/vm.c74
-rw-r--r--kern/vm.h (renamed from vm.h)50
-rw-r--r--kmalloc.c238
-rw-r--r--kmalloc.h7
-rw-r--r--ksan.c132
-rw-r--r--ksan.h7
-rw-r--r--libc/libc.c34
-rw-r--r--libc/rand.c18
-rw-r--r--libc/rand.h3
-rw-r--r--libc/tinyprintf.c196
-rw-r--r--libc/tinyprintf.h16
-rw-r--r--pid_os/Makefile32
-rw-r--r--pid_os/bits.h78
-rw-r--r--pid_os/dev.h5
-rw-r--r--pid_os/gpio.c19
-rw-r--r--pid_os/gpio.h75
-rw-r--r--pid_os/memmap.ld32
-rw-r--r--pid_os/pidos.c18
-rw-r--r--pid_os/start.s34
-rw-r--r--pid_os/uart.c105
-rw-r--r--pid_os/uart.h18
-rw-r--r--pios.h38
-rw-r--r--pios.mk8
-rw-r--r--plugin/memtrace/Makefile10
-rw-r--r--plugin/memtrace/memtrace.c87
-rw-r--r--prog/ads1115/Makefile32
-rw-r--r--prog/ads1115/ads1115.c35
-rw-r--r--prog/ads1115/ads1115.h13
-rw-r--r--prog/ads1115/main.c16
-rw-r--r--prog/analyzer/Makefile28
-rw-r--r--prog/analyzer/analyzer.c92
-rw-r--r--prog/basic/Makefile14
-rw-r--r--prog/basic/basic.ld20
-rw-r--r--prog/basic/basic.s6
-rw-r--r--prog/gpio_int/Makefile32
-rw-r--r--prog/gpio_int/gpio_int.c31
-rw-r--r--prog/hello/Makefile32
-rw-r--r--prog/hello/hello.c6
-rw-r--r--prog/irq/Makefile32
-rw-r--r--prog/irq/irq.c34
-rw-r--r--prog/mmu/Makefile36
-rw-r--r--prog/mmu/mmu.c38
-rw-r--r--prog/mmu_realtime/Makefile37
-rw-r--r--prog/mmu_realtime/irq.s17
-rw-r--r--prog/mmu_realtime/mmu_realtime.c72
-rw-r--r--prog/san/Makefile36
-rw-r--r--prog/san/san.c70
-rw-r--r--prog/threads/Makefile37
-rw-r--r--prog/threads/irq_asm.s18
-rw-r--r--prog/threads/threads.c76
-rw-r--r--prog/ws2812b/Makefile25
-rw-r--r--prog/ws2812b/lights.c47
-rw-r--r--prog/ws2812b/lights.h49
-rw-r--r--start.s19
-rw-r--r--todo.txt4
-rwxr-xr-xtools/exify/exify.sh7
-rw-r--r--vm.c46
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
diff --git a/.gitignore b/.gitignore
index 4d0920c..fd60095 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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();
-}
diff --git a/defs.mk b/defs.mk
index 3af93bd..e28340a 100644
--- a/defs.mk
+++ b/defs.mk
@@ -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/bits.h b/hello_os/bits.h
index f0f16a2..f0f16a2 100644
--- a/bits.h
+++ b/hello_os/bits.h
diff --git a/dev.h b/hello_os/dev.h
index 1f644f7..1f644f7 100644
--- a/dev.h
+++ b/hello_os/dev.h
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/gpio.h b/hello_os/gpio.h
index 8bffdfc..8bffdfc 100644
--- a/gpio.h
+++ b/hello_os/gpio.h
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())
+ ;
+}
diff --git a/uart.h b/hello_os/uart.h
index b2b32af..e7b655f 100644
--- a/uart.h
+++ b/hello_os/uart.h
@@ -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();
diff --git a/i2c.c b/i2c.c
deleted file mode 100644
index 70fc5c4..0000000
--- a/i2c.c
+++ /dev/null
@@ -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;
-}
diff --git a/i2c.h b/i2c.h
deleted file mode 100644
index ada1983..0000000
--- a/i2c.h
+++ /dev/null
@@ -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
diff --git a/kern.c b/kern.c
deleted file mode 100644
index 5820c0a..0000000
--- a/kern.c
+++ /dev/null
@@ -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
diff --git a/asm.h b/kern/asm.h
index d176d19..1985f94 100644
--- a/asm.h
+++ b/kern/asm.h
@@ -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");
+}
diff --git a/gpio.c b/kern/gpio.c
index 13e0671..b44c2cb 100644
--- a/gpio.c
+++ b/kern/gpio.c
@@ -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
diff --git a/sys.h b/kern/sys.h
index 24083cc..7db10eb 100644
--- a/sys.h
+++ b/kern/sys.h
@@ -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)
diff --git a/timer.c b/kern/timer.c
index 492028d..95300c0 100644
--- a/timer.c
+++ b/kern/timer.c
@@ -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;
diff --git a/timer.h b/kern/timer.h
index 6c1f6d2..d0e7e3e 100644
--- a/timer.h
+++ b/kern/timer.h
@@ -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);
+}
diff --git a/uart.c b/kern/uart.c
index b353d1b..e5403ba 100644
--- a/uart.c
+++ b/kern/uart.c
@@ -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();
+}
diff --git a/vm.h b/kern/vm.h
index dc25cce..95bc0bf 100644
--- a/vm.h
+++ b/kern/vm.h
@@ -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);
diff --git a/ksan.c b/ksan.c
deleted file mode 100644
index 500df1f..0000000
--- a/ksan.c
+++ /dev/null
@@ -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
diff --git a/ksan.h b/ksan.h
deleted file mode 100644
index 388da6f..0000000
--- a/ksan.h
+++ /dev/null
@@ -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);
diff --git a/pios.h b/pios.h
deleted file mode 100644
index f161465..0000000
--- a/pios.h
+++ /dev/null
@@ -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, &reg, 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
diff --git a/todo.txt b/todo.txt
index 72901d5..e68cffb 100644
--- a/todo.txt
+++ b/todo.txt
@@ -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);"
diff --git a/vm.c b/vm.c
deleted file mode 100644
index 0953265..0000000
--- a/vm.c
+++ /dev/null
@@ -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);
-}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback