diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-25 15:47:02 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-25 15:47:02 -0700 |
commit | 6d22b0dfc7761a605758552d5824f8039ac5a00f (patch) | |
tree | de0cd4848c02b787d45b41afaca244606eceab5d | |
parent | b07c6f6a9d926d4eac726b94963e479839382675 (diff) | |
download | stm32l4-6d22b0dfc7761a605758552d5824f8039ac5a00f.tar.gz stm32l4-6d22b0dfc7761a605758552d5824f8039ac5a00f.tar.bz2 stm32l4-6d22b0dfc7761a605758552d5824f8039ac5a00f.zip |
Primitive ability to call kernel code from userspace.
-rw-r--r-- | Makefile.preamble | 2 | ||||
-rw-r--r-- | include/kern/mpu/mpu_manager.h | 26 | ||||
-rw-r--r-- | include/kern/priv.h | 2 | ||||
-rw-r--r-- | include/kern/syscall.h | 8 | ||||
-rw-r--r-- | include/kern/syscall/syscall_tbl.inc | 5 | ||||
-rw-r--r-- | include/user/syscall.h | 10 | ||||
-rw-r--r-- | src/kern/init.c | 11 | ||||
-rw-r--r-- | src/kern/log.c | 2 | ||||
-rw-r--r-- | src/kern/main.c | 140 | ||||
-rw-r--r-- | src/kern/mpu/mpu_manager.c | 103 | ||||
-rw-r--r-- | src/kern/panic.c | 1 | ||||
-rw-r--r-- | src/kern/priv.c | 88 | ||||
-rw-r--r-- | src/kern/svc.c | 51 | ||||
-rw-r--r-- | src/kern/syscalls/logs.c | 7 | ||||
-rw-r--r-- | src/user/syscall.c | 17 |
15 files changed, 249 insertions, 224 deletions
diff --git a/Makefile.preamble b/Makefile.preamble index b338833..f6e1370 100644 --- a/Makefile.preamble +++ b/Makefile.preamble @@ -2,7 +2,7 @@ OPT?=-O PREFIX?=arm-unknown-eabi- CC=$(PREFIX)gcc LD=$(PREFIX)ld -CFLAGS?=$(OPT) -mcpu=cortex-m4 -mthumb -mimplicit-it -g -lgcc -static -nostartfiles -Iinclude -Iinclude/arch/arm +CFLAGS?=$(OPT) -mcpu=cortex-m4 -mthumb -g -lgcc -static -nostartfiles -Iinclude -Iinclude/arch/arm LD_FLAGS?=-T linker/linker_script.ld -nostdlib --cref -Map linker/main.map -static TEST_PREFIX=x86_64-pc-linux-gnu- diff --git a/include/kern/mpu/mpu_manager.h b/include/kern/mpu/mpu_manager.h index 7c47722..5a0904c 100644 --- a/include/kern/mpu/mpu_manager.h +++ b/include/kern/mpu/mpu_manager.h @@ -55,7 +55,7 @@ typedef enum { /* Both privileged and non-privileged users can access this memory, but only as Read-only.*/ - ACCESS_PERMS_BOTH_RO = 5, + ACCESS_PERMS_BOTH_RO = 6, } access_perms_t; typedef struct { @@ -81,4 +81,28 @@ void mpu_set_enabled(bool enabled); */ void mpu_configure_region(int region_number, memory_region_opts_t* opts); +typedef enum { + PRIVILEGED, + NOT_PRIVILEGED, +} privilege_t; + + +/** Configure a peripheral region with default peripheral attributes. */ +void configure_peripheral_region( + void* peripheral_base, + region_size_t region_size, + privilege_t priv); + +/** Configure a flash region with default flash attributes. */ +void configure_flash_region( + void* flash_base, + region_size_t region_size, + privilege_t priv); + +/** Configure a ram region with default ram attributes. */ +void configure_ram_region( + void* ram_base, + region_size_t region_size, + privilege_t priv); + #endif /* KERN_MPU_MPU_MANAGER_H_ */ diff --git a/include/kern/priv.h b/include/kern/priv.h index 8940b23..35404f4 100644 --- a/include/kern/priv.h +++ b/include/kern/priv.h @@ -10,5 +10,7 @@ void set_control_register(uint32_t reg); /* Enters user mode from privilieged mode. */ void enter_user_mode(); +void jump_to_user_mode(); + #endif /* _KERN_PRIV_H_ */ diff --git a/include/kern/syscall.h b/include/kern/syscall.h new file mode 100644 index 0000000..d39b620 --- /dev/null +++ b/include/kern/syscall.h @@ -0,0 +1,8 @@ +#ifndef KERN_SYSCALL_H_ +#define KERN_SYSCALL_H_ + +#define SYSCALL(id, fn, kernfn, argt) void kernfn(argt arg); +#include "kern/syscall/syscall_tbl.inc" +#undef SYSCALL + +#endif diff --git a/include/kern/syscall/syscall_tbl.inc b/include/kern/syscall/syscall_tbl.inc new file mode 100644 index 0000000..6c4be57 --- /dev/null +++ b/include/kern/syscall/syscall_tbl.inc @@ -0,0 +1,5 @@ +/* + * Defines a table of SYSCALLS. The syscalls need to be void functions that + * a single 32-bit integer as their argument. + */ +SYSCALL(25, logs, kern_logs, const char*) diff --git a/include/user/syscall.h b/include/user/syscall.h new file mode 100644 index 0000000..c420a3b --- /dev/null +++ b/include/user/syscall.h @@ -0,0 +1,10 @@ +#ifndef USER_SYSCALL_H_ +#define USER_SYSCALL_H_ + +/* This defines the full set of system calls accessible from usermode. */ + +#define SYSCALL(id, fn, kernfn, argt) void fn(argt arg); +#include "kern/syscall/syscall_tbl.inc" +#undef SYSCALL + +#endif diff --git a/src/kern/init.c b/src/kern/init.c index 8885c09..c776b4a 100644 --- a/src/kern/init.c +++ b/src/kern/init.c @@ -66,9 +66,6 @@ init1() init3() { - klogf("--- System Restart ---\n"); - klogf("Setting the vector offset table to point to the start of flash.\n"); - /* Set the vector offset table to be at the start * of FLASH memory. */ SCB.vto_r = 0x08000000; @@ -92,10 +89,6 @@ void run_init_routines() ++initfn) { while (initfn == init_boundaries[initlevel] && initlevel < INIT_LEVEL_7) { ++initlevel; - - if (initlevel > 2) { - klogf("[init%d]\n", initlevel); - } } (*initfn)(); @@ -103,11 +96,7 @@ void run_init_routines() while (initlevel < INIT_LEVEL_7) { ++initlevel; - - klogf("[init%d]\n", initlevel); } - - klogf("Initialization Routines Complete. Onto main()\n"); } /* diff --git a/src/kern/log.c b/src/kern/log.c index 3331249..e9bd424 100644 --- a/src/kern/log.c +++ b/src/kern/log.c @@ -18,8 +18,6 @@ init2() regset(USART2.c_r1, usart_txeie, 1); regset(USART2.c_r1, usart_rxneie, 1); usart_set_enabled(&USART2, USART_ENABLE_TX | USART_ENABLE_RX); - - klogf("klog() enabled on USART2\n"); } void klogf(const char* fmt, ...) diff --git a/src/kern/main.c b/src/kern/main.c index 4ed67be..3af8beb 100644 --- a/src/kern/main.c +++ b/src/kern/main.c @@ -8,6 +8,7 @@ #include "kern/mpu/mpu_manager.h" #include "kern/panic.h" #include "kern/priv.h" +#include "user/syscall.h" void on_hard_fault() { @@ -19,139 +20,34 @@ void on_systick() /* Overrides weak-symbol on_systick. */ klogf("Systick\n"); } -#ifdef ARCH_STM32L4 +void configure_mpu() +{ + configure_flash_region((void*)0x08000000, REGION_SIZE_256Kb, NOT_PRIVILEGED); + configure_ram_region((void*)SRAM1_BASE, REGION_SIZE_64Kb, NOT_PRIVILEGED); + configure_ram_region((void*)SRAM2_BASE, REGION_SIZE_16Kb, NOT_PRIVILEGED); + configure_peripheral_region((void*)0x40000000, REGION_SIZE_512Mb, PRIVILEGED); + mpu_set_enabled(1); +} -int thing_in_sram_1; +#ifdef ARCH_STM32L4 /* Main function. This gets executed from the interrupt vector defined above. */ int main() { - klogf("Hello, World! Clock Mhz: %d\n", (uint32_t)get_clock_mhz()); - klogf("Heap Start: %p\n", &HEAP_START); - klogf("Heap End : %p\n", &HEAP_STOP); - - klogf("mpu: %p\n", &MPU); - klogf("mpu.type_r: %p\n", MPU.type_r); - klogf("mpu.ctrl_r: %p\n", MPU.ctrl_r); - klogf("mpu.rn_r: %p\n", MPU.rn_r); - - thing_in_sram_1 = 0xdeadbeef; - - uint32_t control; - asm volatile("mrs %0, control" : "=r"(control) :); - - /* Set the countdown to start from 10,000,0000. */ - SCB.strv_r = 10000000 / 20; - - /* Enable interrupts. */ - // regset(SCB.stcs_r, scb_tickint, 1); - - /* Start the systick. */ - regset(SCB.stcs_r, scb_enable, 1); - - - klogf("&thing_in_sram_1: %p\n", &thing_in_sram_1); - klogf(" thing_in_sram_1: %p\n", thing_in_sram_1); - mpu_set_enabled(0); - - memory_region_opts_t memopts = { 0 }; - memopts.region = (void*) 0x08000000 /* Flash base */ ; - memopts.bufferable = 0; - memopts.cacheable = 1; - memopts.sharable = 0; - memopts.tex = 0; - memopts.size = REGION_SIZE_256Kb; - memopts.perms = ACCESS_PERMS_ONLY_PRIV_RO; - memopts.subregion_disable = 0; - memopts.executable = 1; - memopts.enable = 1; + configure_mpu(); - mpu_configure_region(0, &memopts); + klogf("Outside of usermode, I can still log stuff using klogf()\n"); - memopts.region = (void*) SRAM1_BASE; - memopts.bufferable = 0; - memopts.cacheable = 1; - memopts.sharable = 0; - memopts.tex = 0; - memopts.size = REGION_SIZE_64Kb; - memopts.perms = ACCESS_PERMS_FULL; - memopts.subregion_disable = 0; - memopts.executable = 1; - memopts.enable = 1; - - mpu_configure_region(1, &memopts); - - memopts.region = (void*) SRAM2_BASE; - memopts.bufferable = 0; - memopts.cacheable = 1; - memopts.sharable = 0; - memopts.tex = 0; - memopts.size = REGION_SIZE_16Kb; - memopts.perms = ACCESS_PERMS_FULL; - memopts.subregion_disable = 0; - memopts.executable = 1; - memopts.enable = 1; - - mpu_configure_region(2, &memopts); - - memopts.region = (void*) 0x40000000 /* Peripheral base. */; - memopts.bufferable = 1; - memopts.cacheable = 0; - memopts.sharable = 1; - memopts.tex = 0; - memopts.size = REGION_SIZE_512Mb; - memopts.perms = ACCESS_PERMS_ONLY_PRIV; - memopts.subregion_disable = 0; - memopts.executable = 0; - memopts.enable = 1; - - mpu_configure_region(3, &memopts); - - for (uint32_t i = 0; i < 8; ++ i) { - MPU.rn_r = i; - klogf("--- %d ---\n", i); - klogf("mpu: %p\n", &MPU); - klogf("mpu.type_r: %p\n", MPU.type_r); - klogf("mpu.ctrl_r: %p\n", MPU.ctrl_r); - klogf("mpu.rn_r: %p\n", MPU.rn_r); - klogf("mpu.ras_r: %p\n", MPU.ras_r); - klogf("mpu.rba_r: %p\n", MPU.rba_r); - } - - // memopts.region = (void*) (SRAM1_BASE); - // memopts.bufferable = 0; - // memopts.cacheable = 1; - // memopts.sharable = 1; - // memopts.tex = 0; - // memopts.size = REGION_SIZE_16Kb; - // memopts.perms = ACCESS_PERMS_NO_ACCESS; - - klogf("CONTROL: %p\n", get_control_register()); - klogf("CONTROL: %p\n", get_control_register()); - klogf("MPU not enabled\n"); - - volatile int x; - klogf("x location: %p\n", &x); - - // mpu_set_enabled(1); - - x = 5; - klogf("Still alive?\n"); - - klogf("Entering User Mode\n"); enter_user_mode(); - asm volatile ( - "svc #21\n" - ); - - klogf("Should Kernel Panic\n"); + logs("Now that I'm in user mode, I have to log stuff using a system call\n"); + logs( + "because I no longer have direct accss to USART2 and cannot use\n" + "klogf()\n"); - for(;;); - // klogf("MPU enabled\n"); - // klogf("&thing_in_sram_1: %p\n", &thing_in_sram_1); - // klogf(" thing_in_sram_1: %p\n", thing_in_sram_1); + for (;;) + ; } #endif diff --git a/src/kern/mpu/mpu_manager.c b/src/kern/mpu/mpu_manager.c index 614766a..0d03c39 100644 --- a/src/kern/mpu/mpu_manager.c +++ b/src/kern/mpu/mpu_manager.c @@ -1,6 +1,6 @@ -#include "arch.h" #include "kern/mpu/mpu_manager.h" +#include "arch.h" #include "arch/arm/cortex-m4/mpu.h" #include "kern/common.h" #include "kern/log.h" @@ -40,8 +40,6 @@ void mpu_configure_region(int region_number, memory_region_opts_t* opts) uint32_t rbar = region; regset(rbar, mpu_region, region_number); regset(rbar, mpu_valid, 1); - - klogf("Writing RBAR: %p\n", rbar); uint32_t rasr = 0; regset(rasr, mpu_en, opts->enable); @@ -56,8 +54,103 @@ void mpu_configure_region(int region_number, memory_region_opts_t* opts) regset(rasr, mpu_ap, opts->perms); regset(rasr, mpu_xn, !opts->executable); - klogf("Writing RASR: %p\n", rasr); - MPU.rba_r = rbar; MPU.ras_r = rasr; } + +static int find_unused_region_slot() +{ + // memory_region_opts_t memory_regions[8]; + + int i; + for (i = 0; i < sizeof(memory_regions) / sizeof(memory_region_opts_t); + ++i) { + if (!memory_regions[i].enable) { + return i; + } + } + + return i; +} + +void configure_peripheral_region( + void* peripheral_base, region_size_t region_size, privilege_t priv) +{ + int idx = find_unused_region_slot(); + + memory_region_opts_t memopts = {0}; + + memopts.region = peripheral_base; + memopts.bufferable = 1; + memopts.cacheable = 0; + memopts.sharable = 1; + memopts.tex = 0; + memopts.size = region_size; + switch (priv) { + case NOT_PRIVILEGED: + memopts.perms = ACCESS_PERMS_FULL; + break; + case PRIVILEGED: + memopts.perms = ACCESS_PERMS_ONLY_PRIV; + break; + } + memopts.subregion_disable = 0; + memopts.executable = 0; + memopts.enable = 1; + + mpu_configure_region(idx, &memopts); +} + +void configure_flash_region( + void* flash_base, region_size_t region_size, privilege_t priv) +{ + int idx = find_unused_region_slot(); + + memory_region_opts_t memopts = {0}; + memopts.region = flash_base; + memopts.bufferable = 0; + memopts.cacheable = 1; + memopts.sharable = 0; + memopts.tex = 0; + memopts.size = region_size; + switch (priv) { + case NOT_PRIVILEGED: + memopts.perms = ACCESS_PERMS_BOTH_RO; + break; + case PRIVILEGED: + memopts.perms = ACCESS_PERMS_ONLY_PRIV_RO; + break; + } + memopts.subregion_disable = 0; + memopts.executable = 1; + memopts.enable = 1; + + mpu_configure_region(idx, &memopts); +} + +void configure_ram_region( + void* ram_base, region_size_t region_size, privilege_t priv) +{ + int idx = find_unused_region_slot(); + + memory_region_opts_t memopts = {0}; + memopts.region = ram_base; + memopts.bufferable = 0; + memopts.cacheable = 1; + memopts.sharable = 0; + memopts.tex = 0; + memopts.size = region_size; + switch (priv) { + case NOT_PRIVILEGED: + memopts.perms = ACCESS_PERMS_FULL; + break; + case PRIVILEGED: + memopts.perms = ACCESS_PERMS_ONLY_PRIV; + break; + } + memopts.subregion_disable = 0; + memopts.executable = 0; + memopts.enable = 1; + + mpu_configure_region(idx, &memopts); +} diff --git a/src/kern/panic.c b/src/kern/panic.c index 3e67b90..de1d143 100644 --- a/src/kern/panic.c +++ b/src/kern/panic.c @@ -28,7 +28,6 @@ _Noreturn void panic(const char* fmt, ...) kerr_logf(" (%p) %p\n", &base[i], base[i]); } - set_system_clock_MHz(4); /* reduce power usage while we do nothing. */ for(;;); } else { diff --git a/src/kern/priv.c b/src/kern/priv.c index 085de85..3162639 100644 --- a/src/kern/priv.c +++ b/src/kern/priv.c @@ -3,87 +3,6 @@ #include "arch.h" #include "kern/log.h" -void handle_svc_call(uint32_t svc_number) -{ - klogf("Handle SVC: %p\n", svc_number); - for (;;) - ; -} - -asm(" .align 2\n" - " .global on_svc\n" - " .syntax unified\n" - " .fpu softvfp\n" - " .type on_svc, %function\n" - "on_svc:\n" - " tst lr,#4\n" - " ite eq\n" - " moveq r12,sp\n" - " mrsne r12,psp\n" - " ldr r12, [r12, #24]\n" - " ldrh r12, [r12, #-2]\n" - " bics r12, r12, #0xff00\n" - " push {r4, lr}\n" - " mov r0 , r12\n" - " bl handle_svc_call\n" - " pop {r4, lr}\n" - " tst lr, #4\n" - " ite eq\n" - " moveq r12,sp\n" - " mrsne r12,psp\n" - " stm r12,{r0-r3}\n" - " bx lr\n"); - -// void on_svc() // ISR handler. Override from weak symbol. -// { -// asm volatile( -// "push {r0-r12, lr}\n\t" -// "ldr r0, [lr, #-4]\n\t" -// "bic r0, r0, #0xff000000\n\t" -// ); - -// TST LR,#4 ; Called from Handler Mode? -// MRSNE R12,PSP ; Yes, use PSP -// MOVEQ R12,SP ; No, use MSP -// LDR R12,[R12,#24] ; Read Saved PC from Stack -// LDRH R12,[R12,#-2] ; Load Halfword -// BICS R12,R12,#0xFF00 ; Extract SVC Number -// uint32_t reg; -// asm volatile( -// "mov r12, sp\n\t" -// "ldr r12, [r12,#24]\n\t" -// // "ldrh r12,[r12, #-2]\n\t" -// // "bics r12, r12, #0xff00\n\t" -// "mov %0, r12\n\t": "=r"(reg)); - -// uint32_t base[0]; -// uint32_t reg; -// -// -// asm volatile("mov %0, sp\n\t" : "=r"(reg)); -// uint32_t* at = (uint32_t*) (reg + 44); /* Does GCC set up 5 stack frame -// words? */ -// -// klogf("Stack pointer: %p\n", reg); -// klogf("Stack pointer +44: %p\n", (reg + 44)); -// klogf("At_: %p: %p\n\n", 0x80009f6, *(uint32_t*)0x80009f6); -// klogf("At: %p: %p\n\n", at, *at); -// -// -// int i = 0; -// for (; i < 20 && &base[i] != (void*)STACK_TOP; ++ i) { -// kerr_logf(" (%p) %p\n", &base[i], base[i]); -// } -// -// // klogf("TEST %p\n", reg); -// -// for(;;); - -// register int svc_number asm ("r0"); - -// klogf("SVC #: %p\n", svc_number); -// } - void set_control_register(uint32_t reg) { asm volatile("msr control, %0" : "=r"(reg) :); @@ -102,3 +21,10 @@ void enter_user_mode() "mov r0, #1\n\t" "msr control, r0\n\t"); } + +void jump_to_user_mode() +{ + asm volatile( + "mov r0, #1\n\t" + "msr control, r0\n\t"); +} diff --git a/src/kern/svc.c b/src/kern/svc.c new file mode 100644 index 0000000..5527364 --- /dev/null +++ b/src/kern/svc.c @@ -0,0 +1,51 @@ +#include "arch.h" +#include "kern/common.h" +#include "kern/log.h" +#include "kern/syscall.h" + +void handle_svc_call( + uint32_t syscall_id, uint32_t syscall_arg, uint32_t svc_number) +{ + switch (svc_number) { + case 0x04: + switch (syscall_id) { +#define SYSCALL(id, fn, kernfn, argt) \ + case id: \ + kernfn((argt)syscall_arg); \ + break; +#include "kern/syscall/syscall_tbl.inc" +#undef SYSCALL + } + break; + + default: + /* An illegal syscall. TODO kill whatever is happening. */ + break; + } +} + +/* The actual handling for the svc call. Overrides the weak + * symbol on_svc in irq.h */ +asm(" .align 2\n" + " .global on_svc\n" + " .syntax unified\n" + " .fpu softvfp\n" + " .type on_svc, %function\n" + "on_svc:\n" + " tst lr,#4\n" + " ite eq\n" + " moveq r12,sp\n" + " mrsne r12,psp\n" + " ldr r12, [r12, #24]\n" + " ldrh r12, [r12, #-2]\n" + " bics r12, r12, #0xff00\n" + " push {r4, lr}\n" + " mov r2 , r12\n" + " bl handle_svc_call\n" + " pop {r4, lr}\n" + " tst lr, #4\n" + " ite eq\n" + " moveq r12,sp\n" + " mrsne r12,psp\n" + " stm r12,{r0-r3}\n" + " bx lr\n"); diff --git a/src/kern/syscalls/logs.c b/src/kern/syscalls/logs.c new file mode 100644 index 0000000..855672c --- /dev/null +++ b/src/kern/syscalls/logs.c @@ -0,0 +1,7 @@ +#include "kern/syscall.h" +#include "kern/log.h" + +void kern_logs(const char* str) +{ + klogf("[Log] - %s", str); +} diff --git a/src/user/syscall.c b/src/user/syscall.c new file mode 100644 index 0000000..3aa0707 --- /dev/null +++ b/src/user/syscall.c @@ -0,0 +1,17 @@ +#include "user/syscall.h" + +#include <stdint.h> + +void __attribute__ ((noinline)) do_syscall( + volatile uint32_t id, + volatile uint32_t arg) +{ + asm volatile("svc #0x04"); +} + +#define SYSCALL(id, fn, kernfn, argt) \ + void fn(argt arg) \ +{ \ + do_syscall(id, (uint32_t) arg); \ +} +#include "kern/syscall/syscall_tbl.inc" |