From 05f5f586c38b0dcca61101f2f5aa15417cf79ca9 Mon Sep 17 00:00:00 2001 From: stevenewald Date: Thu, 14 Nov 2024 16:41:07 -0600 Subject: [PATCH] Working mpu --- edge_os.ld | 73 +------------------ include/ipc/ipc_manager.hpp | 2 +- include/scheduler.hpp | 69 ------------------ include/scheduler/scheduler.hpp | 45 ++++++++++++ include/scheduler/task.hpp | 33 +++++++++ include/userlib/syscalls.hpp | 13 +--- include/util.hpp | 2 + src/fault_handler.cpp | 2 +- src/main.cpp | 13 ++-- src/raw_fault_handling.cpp | 7 +- src/scheduler.cpp | 44 ++++++++++- src/svc.cpp | 2 +- src/{user/user_syscalls.cpp => syscalls.cpp} | 25 ++++--- ...r_main1.cpp => user_program_exception.cpp} | 8 +- ..._main0.cpp => user_program_ipc_part_1.cpp} | 5 +- ..._main2.cpp => user_program_ipc_part_2.cpp} | 2 +- 16 files changed, 165 insertions(+), 180 deletions(-) delete mode 100644 include/scheduler.hpp create mode 100644 include/scheduler/scheduler.hpp create mode 100644 include/scheduler/task.hpp rename src/{user/user_syscalls.cpp => syscalls.cpp} (76%) rename src/user/{user_main1.cpp => user_program_exception.cpp} (76%) rename src/user/{user_main0.cpp => user_program_ipc_part_1.cpp} (85%) rename src/user/{user_main2.cpp => user_program_ipc_part_2.cpp} (96%) diff --git a/edge_os.ld b/edge_os.ld index 176b87d5..79ffe58a 100644 --- a/edge_os.ld +++ b/edge_os.ld @@ -22,26 +22,13 @@ SECTIONS KEEP(*(.svc_data)) PROVIDE(__stop_svc_data = .); } > RAM - .fs_data : - { - PROVIDE(__start_fs_data = .); - KEEP(*(.fs_data)) - PROVIDE(__stop_fs_data = .); - } > RAM .log_dynamic_data : { PROVIDE(__start_log_dynamic_data = .); KEEP(*(SORT(.log_dynamic_data*))) PROVIDE(__stop_log_dynamic_data = .); } > RAM - .cli_sorted_cmd_ptrs : - { - PROVIDE(__start_cli_sorted_cmd_ptrs = .); - KEEP(*(.cli_sorted_cmd_ptrs)) - PROVIDE(__stop_cli_sorted_cmd_ptrs = .); - } > RAM - . = ALIGN(16384); - .user_programs_data : + .user_programs_data ALIGN(16384) : { PROVIDE(__start_user_programs_data = .); _build/user_*.o(.data*) @@ -53,73 +40,19 @@ SECTIONS SECTIONS { - .pwr_mgmt_data : - { - PROVIDE(__start_pwr_mgmt_data = .); - KEEP(*(SORT(.pwr_mgmt_data*))) - PROVIDE(__stop_pwr_mgmt_data = .); - } > FLASH .log_const_data : { PROVIDE(__start_log_const_data = .); KEEP(*(SORT(.log_const_data*))) PROVIDE(__stop_log_const_data = .); } > FLASH - .nrf_balloc : - { - PROVIDE(__start_nrf_balloc = .); - KEEP(*(.nrf_balloc)) - PROVIDE(__stop_nrf_balloc = .); - } > FLASH - .nrf_queue : - { - PROVIDE(__start_nrf_queue = .); - KEEP(*(.nrf_queue)) - PROVIDE(__stop_nrf_queue = .); - } > FLASH - .cli_command : - { - PROVIDE(__start_cli_command = .); - KEEP(*(.cli_command)) - PROVIDE(__stop_cli_command = .); - } > FLASH - .sdh_stack_observers : - { - PROVIDE(__start_sdh_stack_observers = .); - KEEP(*(SORT(.sdh_stack_observers*))) - PROVIDE(__stop_sdh_stack_observers = .); - } > FLASH - .sdh_req_observers : - { - PROVIDE(__start_sdh_req_observers = .); - KEEP(*(SORT(.sdh_req_observers*))) - PROVIDE(__stop_sdh_req_observers = .); - } > FLASH - .sdh_state_observers : - { - PROVIDE(__start_sdh_state_observers = .); - KEEP(*(SORT(.sdh_state_observers*))) - PROVIDE(__stop_sdh_state_observers = .); - } > FLASH - .sdh_ant_observers : - { - PROVIDE(__start_sdh_ant_observers = .); - KEEP(*(SORT(.sdh_ant_observers*))) - PROVIDE(__stop_sdh_ant_observers = .); - } > FLASH - .sdh_ble_observers : - { - PROVIDE(__start_sdh_ble_observers = .); - KEEP(*(SORT(.sdh_ble_observers*))) - PROVIDE(__stop_sdh_ble_observers = .); - } > FLASH /* TODO: make sure this doesnt cause duplication? */ - . = ALIGN(16384); - .user_programs_code : + .user_programs_code ALIGN(16384) : { PROVIDE(__start_user_programs_code = .); _build/user_*.o(.text*) _build/user_*.o(.rodata*) + KEEP(*(.user_code)) PROVIDE(__end_user_programs_code = .); ASSERT((__end_user_programs_code - __start_user_programs_code) <= 16384, "Error: .user_programs_code section exceeds 16 KB"); } > FLASH diff --git a/include/ipc/ipc_manager.hpp b/include/ipc/ipc_manager.hpp index 5b936ca4..b104327c 100644 --- a/include/ipc/ipc_manager.hpp +++ b/include/ipc/ipc_manager.hpp @@ -5,7 +5,7 @@ namespace edge { class IPCManager { - etl::unordered_map, uint8_t, MAX_PROCESSES> name_to_id; + etl::unordered_map name_to_id; etl::array ipc_communicators{nullptr}; IPCManager() = default; diff --git a/include/scheduler.hpp b/include/scheduler.hpp deleted file mode 100644 index 20720f47..00000000 --- a/include/scheduler.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include "config.hpp" -#include "util.hpp" - -#include - -#include - -static constexpr size_t STACK_SIZE_BYTES = 2048; -static constexpr size_t QUANTUM_MILLIS = 5; - -namespace edge { -extern "C" { -void PendSV_Handler(); -void SVC_Handler(); -} - -class Scheduler { - unsigned current_task_index = 0; - uint8_t slices_remaining = 1; - - class Task { - static constexpr size_t STACK_SIZE_IN_UNSIGNED = - STACK_SIZE_BYTES / sizeof(unsigned); - - // ===== DO NOT REARRANGE THESE ===== - etl::array stack{}; - exception_stack_registers first_stack_frame; - // ================================== - - public: - // needs to point to first_stack_frame - unsigned* stack_ptr_loc{&first_stack_frame.R0}; - - // This is useful if we want to adjust the ratio of driver to process runtime - uint8_t consecutive_quantums_to_run; - - Task( - const exception_stack_registers& initial_stack_frame, - uint8_t initial_priority - ) : - first_stack_frame(initial_stack_frame), - consecutive_quantums_to_run(initial_priority) - {} - }; - - etl::vector task_stack{}; - -public: - unsigned get_current_task() const { return current_task_index; } - - void add_task(void (*function)(void), uint8_t priority = 1); - - void start_scheduler(); - - void change_current_task_priority(uint8_t new_priority); - - void yield_current_task(); - -private: - void handle_first_svc_hit(); - - friend void PendSV_Handler(void); - friend void SVC_Handler(void); -}; - -extern Scheduler scheduler; - -} // namespace edge diff --git a/include/scheduler/scheduler.hpp b/include/scheduler/scheduler.hpp new file mode 100644 index 00000000..6e476ee1 --- /dev/null +++ b/include/scheduler/scheduler.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "config.hpp" +#include "util.hpp" +#include "task.hpp" + +#include + +#include + +static constexpr size_t QUANTUM_MILLIS = 5; + +namespace edge { +extern "C" { +void PendSV_Handler(); +void SVC_Handler(); +} + +class Scheduler { + unsigned current_task_index = 0; + uint8_t slices_remaining = 1; + + etl::vector task_stack{}; + +public: + unsigned get_current_task() const { return current_task_index; } + + void add_task(void (*function)(void), uint8_t priority = 1); + + void start_scheduler(); + + void change_current_task_priority(uint8_t new_priority); + + void yield_current_task(); + +private: + void update_mpu_with_stack() const; + void handle_first_svc_hit(); + + friend void PendSV_Handler(void); + friend void SVC_Handler(void); +}; + +extern Scheduler scheduler; + +} // namespace edge diff --git a/include/scheduler/task.hpp b/include/scheduler/task.hpp new file mode 100644 index 00000000..a6967bc1 --- /dev/null +++ b/include/scheduler/task.hpp @@ -0,0 +1,33 @@ +#pragma once + +namespace edge { +static constexpr size_t STACK_SIZE_BYTES = 2048; + +class Task { + static constexpr size_t STACK_SIZE_IN_UNSIGNED = + (STACK_SIZE_BYTES / sizeof(unsigned)) - sizeof(exception_stack_registers) + - sizeof(unsigned*) - sizeof(uint8_t); + +public: + // ===== DO NOT REARRANGE THESE ===== + // Align for MPU purposes + alignas(STACK_SIZE_BYTES) etl::array stack{}; + exception_stack_registers first_stack_frame; + // ================================== + + // needs to point to first_stack_frame + unsigned* stack_ptr_loc{&first_stack_frame.R0}; + + // This is useful if we want to adjust the ratio of driver to process runtime + uint8_t consecutive_quantums_to_run; + + Task( + const exception_stack_registers& initial_stack_frame, uint8_t initial_priority + ) : + first_stack_frame(initial_stack_frame), + consecutive_quantums_to_run(initial_priority) + {} +}; + +static_assert(sizeof(Task) <= STACK_SIZE_BYTES); +} // namespace edge diff --git a/include/userlib/syscalls.hpp b/include/userlib/syscalls.hpp index 55693c15..e034bfec 100644 --- a/include/userlib/syscalls.hpp +++ b/include/userlib/syscalls.hpp @@ -20,9 +20,9 @@ void get_button_pressed( void (*callback)(drivers::ButtonType, drivers::ButtonState) ); -void send_ipc(const ProcessName& name, uint32_t message); +void send_ipc(const char* name, uint32_t message); -void subscribe_ipc(const ProcessName& name, void (*callback)(int message)); +void subscribe_ipc(const char* name, void (*callback)(int message)); void set_fault_handler(void (*callback)(FaultType)); @@ -30,13 +30,4 @@ void set_fault_handler(void (*callback)(FaultType)); // Technically this is insecure - it's mostly for debugging void debug_print(const char* string); -// yeah i know -template -inline void debug_println(const etl::string& str) -{ - etl::string str2 = str; - str2 += "\n"; - debug_print(str2.data()); -} - } // namespace edge::userlib diff --git a/include/util.hpp b/include/util.hpp index caff8f0e..24ca61b1 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -1,5 +1,7 @@ #pragma once +#define USER_CODE __attribute__((section(".user_code"))) + namespace edge { [[noreturn]] void panic(const char* reason); diff --git a/src/fault_handler.cpp b/src/fault_handler.cpp index cb89f0f8..d89f52f4 100644 --- a/src/fault_handler.cpp +++ b/src/fault_handler.cpp @@ -2,7 +2,7 @@ #include "nrf52.h" #include "pending_process_callbacks.hpp" -#include "scheduler.hpp" +#include "scheduler/scheduler.hpp" #include diff --git a/src/main.cpp b/src/main.cpp index af38cc7d..6e032fde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,14 @@ #include "drivers/driver_enums.hpp" #include "fault_handler.hpp" -#include "scheduler.hpp" +#include "scheduler/scheduler.hpp" #include "util.hpp" #include #include -extern void task0(void); +extern void ipc_part1(void); +extern void ipc_part2(void); +extern void exception_task(void); int main(void) { @@ -14,9 +16,10 @@ int main(void) edge::FaultHandler::get(); - // edge::scheduler.add_task(exception_task); - edge::scheduler.add_task(task0); - // edge::scheduler.add_task(task1); + edge::scheduler.add_task(exception_task); + + edge::scheduler.add_task(ipc_part1); + edge::scheduler.add_task(ipc_part2); edge::scheduler.start_scheduler(); } diff --git a/src/raw_fault_handling.cpp b/src/raw_fault_handling.cpp index 2bb01975..c167a183 100644 --- a/src/raw_fault_handling.cpp +++ b/src/raw_fault_handling.cpp @@ -1,4 +1,7 @@ #include "fault_handler.hpp" +#include "nrf52833.h" + +#include namespace { extern "C" { @@ -32,13 +35,13 @@ void BusFault_Handler_CPP(uint32_t* stack_ptr) FaultHandler::get().fault_triggered(edge::FaultType::Bus, stack_ptr); } -void __attribute__((used, naked)) MemManage_Handler(void) +void __attribute__((used, naked)) MemoryManagement_Handler(void) { asm volatile("TST LR, #4 \n" "ITE EQ \n" "MRSEQ R0, MSP \n" "MRSNE R0, PSP \n" - "B MemManage_Handler_C \n"); + "B MemManage_Handler_CPP \n"); } void MemManage_Handler_CPP(uint32_t* stack_ptr) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 5e633d12..71e0d818 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,8 +1,35 @@ -#include "scheduler.hpp" +#include "scheduler/scheduler.hpp" #include "drivers/driver_commands.hpp" #include "nrf52833.h" #include "pending_process_callbacks.hpp" +#include "util.hpp" + +extern "C" { +extern uint8_t __start_user_programs_code; +extern uint8_t __end_user_programs_code; +extern uint8_t __start_user_programs_data; +extern uint8_t __end_user_programs_data; +} + +namespace { +void initialize_mpu() +{ + MPU->CTRL = 0; + + MPU->RNR = 0; + MPU->RBAR = ((unsigned)(&__start_user_programs_code) & MPU_RBAR_ADDR_Msk); + MPU->RASR = (0b111 << MPU_RASR_AP_Pos) | (13 << MPU_RASR_SIZE_Pos) + | (1 << MPU_RASR_ENABLE_Pos); + + MPU->RNR = 1; + MPU->RBAR = ((unsigned)(&__start_user_programs_data) & MPU_RBAR_ADDR_Msk); + MPU->RASR = (0b011 << MPU_RASR_AP_Pos) | (13 << MPU_RASR_SIZE_Pos) + | (1 << MPU_RASR_ENABLE_Pos); + + MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; +} +} // namespace namespace edge { @@ -20,6 +47,7 @@ void Scheduler::start_scheduler() NVIC_SetPriority(PendSV_IRQn, 0x3); NVIC_SetPriority(SysTick_IRQn, 0x1); + initialize_mpu(); asm volatile("CPSIE I"); asm volatile("SVC #0"); } @@ -31,6 +59,16 @@ void Scheduler::add_task(void (*function)(void), uint8_t priority) ); } +void Scheduler::update_mpu_with_stack() const +{ + const unsigned* current_task_stack = task_stack[current_task_index].stack.begin(); + + MPU->RNR = 2; + MPU->RBAR = (reinterpret_cast(current_task_stack) & MPU_RBAR_ADDR_Msk); + MPU->RASR = (0b011 << MPU_RASR_AP_Pos) | (10 << MPU_RASR_SIZE_Pos) + | (1 << MPU_RASR_ENABLE_Pos); +} + void trigger_pendsv() { SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; @@ -82,6 +120,8 @@ __attribute__((naked, used)) void PendSV_Handler() scheduler.task_stack[scheduler.current_task_index].stack_ptr_loc )); + scheduler.update_mpu_with_stack(); + asm volatile("mrs r0,psp\n" "sub r0,#96\n" "ldm r0!,{r4-r11}\n" @@ -106,7 +146,7 @@ __attribute__((used)) void SysTick_Handler() // Runs in userspace after async callback has finished // I don't think there's any way to make this cleaner lol -__attribute__((used, naked)) void restore_regs() +__attribute__((used, naked)) USER_CODE void restore_regs() { // Load fpscr first so we can avoid dirtying r0 after its popped asm volatile("ldr r0, [sp, #96]\n" diff --git a/src/svc.cpp b/src/svc.cpp index 26176547..4c797829 100644 --- a/src/svc.cpp +++ b/src/svc.cpp @@ -3,7 +3,7 @@ #include "fault_handler.hpp" #include "ipc/ipc_command_types.hpp" #include "ipc/ipc_manager.hpp" -#include "scheduler.hpp" +#include "scheduler/scheduler.hpp" #include "userlib/system_call_type.hpp" #include "util.hpp" diff --git a/src/user/user_syscalls.cpp b/src/syscalls.cpp similarity index 76% rename from src/user/user_syscalls.cpp rename to src/syscalls.cpp index 60f249c8..14ab74a4 100644 --- a/src/user/user_syscalls.cpp +++ b/src/syscalls.cpp @@ -4,6 +4,7 @@ #include "ipc/ipc_command_types.hpp" #include "register_utils.hpp" #include "userlib/system_call_type.hpp" +#include "util.hpp" #include @@ -13,40 +14,40 @@ return ret; namespace edge::userlib { -void change_priority(uint8_t new_priority) +void USER_CODE change_priority(uint8_t new_priority) { SET_REGISTER(r0, new_priority); TRIGGER_SVC(SystemCallType::CHANGE_PRIORITY); } -void yield() +void USER_CODE yield() { TRIGGER_SVC(SystemCallType::YIELD); } -void set_fault_handler(void (*callback)(FaultType)) +void USER_CODE set_fault_handler(void (*callback)(FaultType)) { SET_REGISTER(r0, callback); TRIGGER_SVC(SystemCallType::SET_FAULT_HANDLER); } -void send_ipc(const ProcessName& name, uint32_t message) +void USER_CODE send_ipc(const char* name, uint32_t message) { SET_REGISTER(r0, IPCCommandType::SEND); - SET_REGISTER(r1, name.data()); + SET_REGISTER(r1, name); SET_REGISTER(r2, message); TRIGGER_SVC(SystemCallType::IPC); } -void subscribe_ipc(const ProcessName& name, void (*callback)(int message)) +void USER_CODE subscribe_ipc(const char* name, void (*callback)(int message)) { SET_REGISTER(r0, IPCCommandType::REGISTER); - SET_REGISTER(r1, name.data()); + SET_REGISTER(r1, name); SET_REGISTER(r2, callback); TRIGGER_SVC(SystemCallType::IPC); } -void get_button_pressed( +void USER_CODE get_button_pressed( drivers::ButtonType button_type, void (*callback)(drivers::ButtonType, drivers::ButtonState) ) @@ -57,7 +58,7 @@ void get_button_pressed( TRIGGER_SVC(SystemCallType::SUBSCRIBE); } -void set_led(uint8_t row, uint8_t col, bool enabled) +void USER_CODE set_led(uint8_t row, uint8_t col, bool enabled) { SET_REGISTER(r0, (int)drivers::DriverCommand::LED_DISPLAY); SET_REGISTER(r1, (int)row); @@ -66,7 +67,7 @@ void set_led(uint8_t row, uint8_t col, bool enabled) TRIGGER_SVC(SystemCallType::COMMAND); } -bool get_button_pressed(drivers::ButtonType button_type) +bool USER_CODE get_button_pressed(drivers::ButtonType button_type) { SET_REGISTER(r0, (int)drivers::DriverCommand::BUTTONS); SET_REGISTER(r1, button_type); @@ -74,14 +75,14 @@ bool get_button_pressed(drivers::ButtonType button_type) RETURN_REGISTER(r0); } -int get_time_us() +int USER_CODE get_time_us() { SET_REGISTER(r0, (int)drivers::DriverCommand::GET_TIME); TRIGGER_SVC(SystemCallType::COMMAND); RETURN_REGISTER(r0); } -void debug_print(const char* val) +void USER_CODE debug_print(const char* val) { SET_REGISTER(r0, (int)drivers::DriverCommand::TERMINAL_OUTPUT); SET_REGISTER(r1, (int)val); diff --git a/src/user/user_main1.cpp b/src/user/user_program_exception.cpp similarity index 76% rename from src/user/user_main1.cpp rename to src/user/user_program_exception.cpp index 9c00dc7d..47986048 100644 --- a/src/user/user_main1.cpp +++ b/src/user/user_program_exception.cpp @@ -6,7 +6,7 @@ void exception_task(void) // Usage asm volatile(".word 0xFFFFFFFF"); - // Bus + // Memory volatile uint32_t* invalid_address = (uint32_t*)0xFFFFFFF0; [[maybe_unused]] uint32_t value = *invalid_address; }; @@ -15,13 +15,13 @@ void exception_task(void) static void (*fault_handler)(edge::FaultType) = [](edge::FaultType type) { switch (type) { case edge::FaultType::Usage: - debug_println(etl::string<25>{"USAGE FAULT TRIGGERED"}); + debug_print("USAGE FAULT TRIGGERED\n"); break; case edge::FaultType::Bus: - debug_println(etl::string<25>{"BUS FAULT TRIGGERED"}); + debug_print("BUS FAULT TRIGGERED\n"); break; case edge::FaultType::Memory: - debug_println(etl::string<25>{"MEMORY FAULT TRIGGERED"}); + debug_print("MEMORY FAULT TRIGGERED\n"); break; } }; diff --git a/src/user/user_main0.cpp b/src/user/user_program_ipc_part_1.cpp similarity index 85% rename from src/user/user_main0.cpp rename to src/user/user_program_ipc_part_1.cpp index 2b75cc38..985269a2 100644 --- a/src/user/user_main0.cpp +++ b/src/user/user_program_ipc_part_1.cpp @@ -1,6 +1,9 @@ #include "userlib/syscalls.hpp" +#include "nrf52833.h" +#include "nrf_delay.h" +#include -void task0(void) +void ipc_part1(void) { using namespace edge::userlib; diff --git a/src/user/user_main2.cpp b/src/user/user_program_ipc_part_2.cpp similarity index 96% rename from src/user/user_main2.cpp rename to src/user/user_program_ipc_part_2.cpp index 767fc112..77395efe 100644 --- a/src/user/user_main2.cpp +++ b/src/user/user_program_ipc_part_2.cpp @@ -1,6 +1,6 @@ #include "userlib/syscalls.hpp" -void task1(void) +void ipc_part2(void) { using namespace edge::userlib; using namespace edge::drivers;