summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZachary Yedidia <zyedidia@gmail.com>2022-05-13 15:17:55 -0700
committerZachary Yedidia <zyedidia@gmail.com>2022-05-13 15:17:55 -0700
commit4d16c701e4e498a5d2979cbc194b4e32f2b620b2 (patch)
tree7eb5c46bd53871fdb7f44be6bb984912b3fcb0fd
parent5adca42ff4e8a2a6352408158e062d6b22a677d7 (diff)
parent8c6cb5241097f2943bfe8e69d97371fc1f16cc9c (diff)
Merge branch 'exo' of ssh://github.com/zyedidia/pios into exo
-rw-r--r--kern/Makefile5
-rw-r--r--kern/interrupts-asm.s79
-rw-r--r--kern/interrupts.c13
-rw-r--r--kern/kern.c19
-rw-r--r--kern/proc.c21
-rw-r--r--kern/proc.h1
-rw-r--r--kern/syscall.c4
-rw-r--r--kern/syscall_list.h1
-rw-r--r--kern/timer.c43
-rw-r--r--kern/timer.h6
-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
20 files changed, 563 insertions, 45 deletions
diff --git a/kern/Makefile b/kern/Makefile
index 846ba69..f987b2a 100644
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -54,4 +54,7 @@ p-basic.o:
p-hello.o:
make -C $(PIOS)/hello_os exostall
-.PHONY: format all install
+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/kern/interrupts-asm.s b/kern/interrupts-asm.s
index ee440aa..c90a24c 100644
--- a/kern/interrupts-asm.s
+++ b/kern/interrupts-asm.s
@@ -4,14 +4,14 @@
.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
+ 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
@@ -23,32 +23,39 @@ _fiq_h: .word asm_fiq
_interrupt_table_end:
asm_reset:
- ldr sp, =kstack
- bl reboot
+ ldr sp, =kstack
+ bl reboot
asm_undef_insn:
- ldr sp, =kstack
- ldr pc, _vec_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}^
+ 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
+ ldr sp, =kstack
+ ldr pc, _vec_prefetch_abort
asm_data_abort:
- ldr sp, =kstack
- ldr pc, _vec_data_abort
+ ldr sp, =kstack
+ ldr pc, _vec_data_abort
asm_irq:
- ldr sp, =kstack
- ldr pc, _vec_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
+ ldr sp, =kstack
+ ldr pc, _vec_fiq
.globl _vector_table
_vector_table:
@@ -61,14 +68,14 @@ _vec_fiq: .word vec_fiq
.globl enable_interrupts
enable_interrupts:
- mrs r0, cpsr
- bic r0, r0, #(1 << 7)
- msr cpsr_c, r0
- bx lr
+ 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
+ mrs r0, cpsr
+ orr r0, r0, #(1 << 7)
+ msr cpsr_c, r0
+ bx lr
diff --git a/kern/interrupts.c b/kern/interrupts.c
index f211398..f140212 100644
--- a/kern/interrupts.c
+++ b/kern/interrupts.c
@@ -102,8 +102,17 @@ void __attribute__((interrupt("ABORT"))) vec_data_abort() {
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/kern/kern.c b/kern/kern.c
index 9e36502..a99a8ce 100644
--- a/kern/kern.c
+++ b/kern/kern.c
@@ -10,6 +10,7 @@
#include "sys.h"
#include "uart.h"
#include "vm.h"
+#include "timer.h"
void reboot() {
printf("DONE!!!\n");
@@ -38,15 +39,23 @@ void kernel_start() {
uart_init(115200);
init_printf(NULL, uart_putc);
- irq_init();
+
kmalloc_init();
+ irq_init();
+ irq_enable(BASIC_TIMER_IRQ);
+ timer_irq_load(0x1000);
+
printf("kernel booted\n");
- extern unsigned char _binary_hello_bin_start;
- extern unsigned char _binary_hello_bin_end;
- proc_t *p_hello = proc_new(&_binary_hello_bin_start, (size_t) (&_binary_hello_bin_end - &_binary_hello_bin_start));
- proc_run(p_hello);
+ extern unsigned char _binary_pidos_bin_start;
+ extern unsigned char _binary_pidos_bin_end;
+
+ proc_t *p_pidos_1 = proc_new(&_binary_pidos_bin_start, (size_t) (&_binary_pidos_bin_end - &_binary_pidos_bin_start));
+ proc_new(&_binary_pidos_bin_start, (size_t) (&_binary_pidos_bin_end - &_binary_pidos_bin_start));
+
+ // TODO/NOTE(masot): Currently, proc_run enables IRQs
+ proc_run(p_pidos_1);
reboot();
return;
diff --git a/kern/proc.c b/kern/proc.c
index 4df3f3a..d08fad2 100644
--- a/kern/proc.c
+++ b/kern/proc.c
@@ -42,6 +42,7 @@ void __attribute__((noreturn)) proc_run(proc_t *proc) {
vm_set_pt(proc->pt);
curproc = proc;
+ enable_interrupts(); // TODO: Set this in the SPSR
// NOTE: To use SPSR, need to be sure we are *NOT* in user/system mode.
// TODO(masot): add an assert like that
set_spsr((get_cpsr() & ~0b11111) | 0b10000);
@@ -49,3 +50,23 @@ void __attribute__((noreturn)) proc_run(proc_t *proc) {
while (1) {
}
}
+
+thread_id = 0;
+
+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
index d908d56..592538e 100644
--- a/kern/proc.h
+++ b/kern/proc.h
@@ -48,3 +48,4 @@ extern proc_t *curproc;
proc_t *proc_new(uint8_t *code, size_t codesz);
void proc_run(proc_t *proc);
+void proc_scheduler_irq(regs_t *regs);
diff --git a/kern/syscall.c b/kern/syscall.c
index c108752..b3dab38 100644
--- a/kern/syscall.c
+++ b/kern/syscall.c
@@ -51,9 +51,11 @@ void syscall(regs_t *regs) {
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;
}
- regs->pc += 4;
}
diff --git a/kern/syscall_list.h b/kern/syscall_list.h
index e22d70d..9e4366a 100644
--- a/kern/syscall_list.h
+++ b/kern/syscall_list.h
@@ -4,6 +4,7 @@
#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
diff --git a/kern/timer.c b/kern/timer.c
new file mode 100644
index 0000000..addfbcf
--- /dev/null
+++ b/kern/timer.c
@@ -0,0 +1,43 @@
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t load;
+ uint32_t value;
+ uint32_t ctrl;
+ uint32_t irq_clear;
+ uint32_t raw_irq;
+ uint32_t masked_irq;
+ uint32_t reload;
+ uint32_t pre_divider;
+ uint32_t free_running_counter;
+} timer_t;
+
+#define TIMER_CTRL_32BIT (1 << 1)
+
+#define TIMER_CTRL_PRESCALE_1 (0 << 2)
+#define TIMER_CTRL_PRESCALE_16 (1 << 2)
+#define TIMER_CTRL_PRESCALE_256 (2 << 2)
+
+#define TIMER_CTRL_INT_ENABLE (1 << 5)
+#define TIMER_CTRL_INT_DISABLE (0 << 5)
+
+#define TIMER_CTRL_ENABLE (1 << 7)
+#define TIMER_CTRL_DISABLE (0 << 7)
+
+#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;
+ timer->ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_INT_ENABLE |
+ TIMER_CTRL_PRESCALE_256;
+}
+
+bool timer_has_irq() {
+ return timer->masked_irq;
+}
+
+void timer_clear_irq() {
+ timer->irq_clear = 1;
+}
diff --git a/kern/timer.h b/kern/timer.h
index 95c22b7..28840b5 100644
--- a/kern/timer.h
+++ b/kern/timer.h
@@ -1,6 +1,8 @@
#pragma once
#include "sys.h"
+#include <stdbool.h>
+#include <stdint.h>
static inline void timer_init() {
asm volatile("mcr p15, 0, %0, c15, c12, 0" ::"r"(1));
@@ -34,3 +36,7 @@ static inline void delay_us(unsigned us) {
static inline void delay_ms(unsigned ms) {
delay_us(ms * 1000);
}
+
+void timer_irq_load(uint32_t load);
+bool timer_has_irq();
+void timer_clear_irq();
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);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback