From baedda497d16c5096971eee83a0c467fe663fe6d Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 2 Jan 2016 21:13:31 +0100 Subject: o Moving around a lot of files. --- apps/os1/CMakeLists.txt | 23 ++++ apps/os1/os1.cpp | 285 ++++++++++++++++++++++++++++++++++++++++++++++++ apps/os1/os1_cm3.s | 56 ++++++++++ 3 files changed, 364 insertions(+) create mode 100644 apps/os1/CMakeLists.txt create mode 100644 apps/os1/os1.cpp create mode 100644 apps/os1/os1_cm3.s (limited to 'apps/os1') diff --git a/apps/os1/CMakeLists.txt b/apps/os1/CMakeLists.txt new file mode 100644 index 0000000..b6849b7 --- /dev/null +++ b/apps/os1/CMakeLists.txt @@ -0,0 +1,23 @@ +add_executable(os1.elf os1.cpp os1_cm3.s + ${PLAYGROUND_DIR}/src/init_low.s ${PLAYGROUND_DIR}/src/init_high.cpp ${PLAYGROUND_DIR}/include/init_high.h + ${PLAYGROUND_DIR}/include/playground.h + ${PLAYGROUND_DIR}/src/debug.cpp ${PLAYGROUND_DIR}/include/debug.h + ${PLAYGROUND_DIR}/include/stm32f10x_conf.h + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport/core_cm3.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/misc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_rcc.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_usart.c + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c + ) +target_link_libraries(os1.elf tinyprintf) + +target_include_directories(os1.elf PUBLIC + ${PLAYGROUND_DIR}/include + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/CoreSupport + ${STM32F10X_STDPERIPH_LIB}/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x + ${STM32F10X_STDPERIPH_LIB}/Libraries/STM32F10x_StdPeriph_Driver/inc) +target_compile_definitions(os1.elf PUBLIC ${STM32F10X_STDPERIPH_DEFINES}) + +set_target_properties(os1.elf PROPERTIES LINK_FLAGS "-nostartfiles -T${CMAKE_SOURCE_DIR}/cmake/stm32.ld") +add_extra_commands(os1.elf) diff --git a/apps/os1/os1.cpp b/apps/os1/os1.cpp new file mode 100644 index 0000000..9c87a3d --- /dev/null +++ b/apps/os1/os1.cpp @@ -0,0 +1,285 @@ +#include +#include +#include +#include + +#include "debug.h" +#include "tinyprintf.h" +#include "playground.h" + +extern "C" +__attribute__((naked, used)) +void HardFault_Handler_C(uint32_t *hardfault_args) { + dbg_printf("r0 = 0x%08lx (%lu)\n", hardfault_args[0], hardfault_args[0]); + dbg_printf("r1 = 0x%08lx (%lu)\n", hardfault_args[1], hardfault_args[1]); + dbg_printf("r2 = 0x%08lx (%lu)\n", hardfault_args[2], hardfault_args[2]); + dbg_printf("r3 = 0x%08lx (%lu)\n", hardfault_args[3], hardfault_args[3]); + dbg_printf("r12 = 0x%08lx (%lu)\n", hardfault_args[4], hardfault_args[4]); + dbg_printf("lr = 0x%08lx (%lu)\n", hardfault_args[5], hardfault_args[5]); + dbg_printf("pc = 0x%08lx (%lu)\n", hardfault_args[6], hardfault_args[6]); + dbg_printf("psr = 0x%08lx (%lu)\n", hardfault_args[7], hardfault_args[7]); + dbg_printf("\n"); + + halt(); +} + +enum class exc_return_t : uint32_t { + RETURN_TO_HANDLER_MODE_USE_MSP = 0xFFFFFFF1, + RETURN_TO_THREAD_MODE_USE_MSP = 0xFFFFFFF9, + RETURN_TO_THREAD_MODE_USE_PSP = 0xFFFFFFFD, +}; + +// This is used from assembly so order is important +struct task_t { + uint8_t *stack; + exc_return_t exc_return; + int flags; + + void init(uint8_t *stack) { + this->stack = stack; + flags = 0x01; + set_ready(); + } + + void deinit() { + flags = 0; + } + + bool is_ready() { + return (flags & 0x02) > 0; + } + + void set_ready() { + flags |= 0x02; + } +} __attribute__((packed)); + +const int max_task_count = 3; +const int stack_size = 100; + +task_t tasks[max_task_count]; +uint8_t stacks[max_task_count][stack_size]; +uint8_t task_count = 0; +int current_task; + +const unsigned int SYSTICK_FREQUENCY_HZ = 10; + +struct hardware_frame_t { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r12; + uint32_t lr; + uint32_t pc; + uint32_t psr; +}; + +struct software_frame_t { + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; +}; + +extern "C" +void SysTick_Handler() { + static bool on = true; + + if (on) { + GPIO_SetBits(GPIOB, GPIO_Pin_7); + } + else { + GPIO_ResetBits(GPIOB, GPIO_Pin_7); + } + + on = !on; + + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; +} + +void thread_end() { +} + +volatile bool idle_task_run; + +void idle_task(const void *const) { + // trigger PendSV to run + SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk; + + // wait for the PendSV handler to kick in. After the handler has completed it will do a context switch and + // this point shouldn't be reached. + + idle_task_run = true; + while (idle_task_run) { + GPIOB->BSRR = GPIO_Pin_6; + GPIOB->BRR = GPIO_Pin_6; + } +} + +static +void os_create_thread(void (task)(void const *const), bool create_sw); + +void os_init() { + NVIC_SetPriority(SysTick_IRQn, 0xff); + NVIC_SetPriority(PendSV_IRQn, 0xff); + + SysTick_Config(SystemCoreClock / SYSTICK_FREQUENCY_HZ); + + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + init.GPIO_Mode = GPIO_Mode_Out_PP; + init.GPIO_Pin = GPIO_Pin_6; + GPIO_Init(GPIOB, &init); + init.GPIO_Pin = GPIO_Pin_7; + GPIO_Init(GPIOB, &init); + + for (int i = 0; i < max_task_count; i++) { + tasks[i].flags = 0; + } + + os_create_thread(idle_task, false); + current_task = 0; +} + +void os_create_thread(void (task)(void const *const)) { + os_create_thread(task, true); +} + +static +void os_create_thread(void (task)(void const *const), bool create_sw) { + uint8_t *s = stacks[task_count] + stack_size; + + s -= sizeof(hardware_frame_t); + hardware_frame_t *hw = reinterpret_cast(s); + + hw->r0 = 0x00000000; + hw->r1 = 0x01010101; + hw->r2 = 0x02020202; + hw->r3 = 0x03030303; + hw->r12 = 0x0c0c0c0c; + hw->lr = reinterpret_cast(thread_end); + + hw->pc = reinterpret_cast(task); + hw->psr = 0x01000000; + + if (create_sw) { + s -= sizeof(software_frame_t); + software_frame_t *sw = reinterpret_cast(s); + + sw->r4 = 0x04040404; + sw->r5 = 0x05050505; + sw->r6 = 0x06060606; + sw->r7 = 0x07070707; + sw->r8 = 0x08080808; + sw->r9 = 0x09090909; + sw->r10 = 0x0a0a0a0a; + sw->r11 = 0x0b0b0b0b; + } + + task_t *t = &tasks[task_count]; + t->init(s); + t->exc_return = exc_return_t::RETURN_TO_THREAD_MODE_USE_PSP; + + task_count++; +} + +static +int find_first_ready_task() { + task_t *t; + int idx = current_task + 1; + do { + if (idx == max_task_count) { + idx = 1; + } else if (idx == current_task) { + return 0; + } + + t = &tasks[idx]; + } while (!t->is_ready()); + + return idx; +} + +__attribute__((used)) +task_t *select_next_task(uint8_t *current_stack) { + + task_t *t = &tasks[current_task]; + int new_task = find_first_ready_task(); + + if (new_task != current_task) { + t->stack = current_stack; + t = &tasks[new_task]; + current_task = new_task; + } + + return t; +} + +volatile bool run; + +extern "C" void do_first_context_switch(uint8_t *user_stack, void (task)(const void *const arg)); + +void os_start() { + run = true; + + task_t &t = tasks[0]; + + do_first_context_switch(t.stack, idle_task); + + while (run) { + } +} + + +volatile bool run1 = true; + +void job1(void const *const) { + while (run1) { + GPIO_SetBits(GPIOB, GPIO_Pin_8); + GPIO_ResetBits(GPIOB, GPIO_Pin_8); + } +} + +volatile bool run2 = true; + +void job2(void const *const) { + while (run2) { + GPIO_SetBits(GPIOB, GPIO_Pin_5); + GPIO_ResetBits(GPIOB, GPIO_Pin_5); + } +} + +int main(void) { + SystemInit(); + + init_printf(nullptr, dbg_putc); + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO + | RCC_APB2Periph_USART1 + | RCC_APB2Periph_GPIOA + | RCC_APB2Periph_GPIOB + | RCC_APB2Periph_GPIOC, + ENABLE); + + RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, ENABLE); + RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE); + + // Make Port B's pin #5 the debug output pin + GPIO_InitTypeDef init; + GPIO_StructInit(&init); + init.GPIO_Mode = GPIO_Mode_Out_PP; + init.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_8; + GPIO_Init(GPIOB, &init); + + os_init(); + os_create_thread(job1); + os_create_thread(job2); + os_start(); + + return 0; +} diff --git a/apps/os1/os1_cm3.s b/apps/os1/os1_cm3.s new file mode 100644 index 0000000..a9083dc --- /dev/null +++ b/apps/os1/os1_cm3.s @@ -0,0 +1,56 @@ +.syntax unified +.cpu cortex-m3 +.thumb + +.section .text + +/* + +User threads use the process stack (PSP register), kernel and exception code use the main stack (MSP register). + +*/ + +.thumb_func +.global do_first_context_switch +// void do_first_context_switch(uint8_t *user_stack, void (task)(const void *arg)); +do_first_context_switch: + /* Set PSP to the user task's stack */ + msr psp, r0 + + // Set CONTROL.SPSEL=1 so that we run with two stacks + mov r0, #2 + msr control, r0 + isb + + // Restore the data from hardware_frame_t. + pop {r0 - r3, r12, lr} + // Pop PC and PSR. PSR is ignored, but we branch to the new PC + pop {r4, r5} + bx r4 + +/* +When this function is executed {r0-r3,r12,lr,pc} has been pushed to the stack pointed to by PSP. We push the rest of the +registers to the PSP. The current stack pointer is the MSP. + */ +.thumb_func +.global PendSV_Handler +PendSV_Handler: + // Save the rest of the context to the current process' stack + mrs r0, psp + stmdb r0!, {r4 - r11} + + // Call select_next_task_sp. after return, r0 points to a task_t + bl _Z16select_next_taskPh // task_t *select_next_task(uint8_t *current_stack) + + // load task_t.stack and task_t.lr into r1 and lr + ldm r0, {r1, lr} + + ldmia r1!, {r4 - r11} + msr psp, r1 + + // Return, let the CPU restore the hardware part of the context + bx lr +.pool +.size PendSV_Handler,.-PendSV_Handler + +.end -- cgit v1.2.3