Skip to content

Commit

Permalink
Merge pull request #25 from stevenewald/stack-struct
Browse files Browse the repository at this point in the history
Added abstraction to exception stack registers
  • Loading branch information
stevenewald authored Nov 13, 2024
2 parents 72717b0 + d45fd35 commit 933cf40
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 62 deletions.
28 changes: 7 additions & 21 deletions include/scheduler.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "config.hpp"
#include "util.hpp"

#include <stdio.h>

Expand All @@ -15,24 +15,6 @@ void PendSV_Handler();
void SVC_Handler();
}

struct stack_registers {
unsigned R0{};
unsigned R1{};
unsigned R2{};
unsigned R3{};
unsigned R12{};
unsigned LR{};
unsigned RETURN_ADDR{};
unsigned CTRL{0x01000000};
unsigned FP_REGS[16]{};
unsigned FPSCR{};

// diagram: https://shorturl.at/85lyY
unsigned RESERVED_FOR_STACK_ALIGNMENT[2];

stack_registers(unsigned return_addr) : RETURN_ADDR(return_addr) {}
};

class Scheduler {
unsigned current_task_index = 0;
uint8_t slices_remaining = 1;
Expand All @@ -43,7 +25,7 @@ class Scheduler {

// ===== DO NOT REARRANGE THESE =====
etl::array<unsigned, STACK_SIZE_IN_UNSIGNED> stack{};
stack_registers first_stack_frame;
exception_stack_registers first_stack_frame;
// ==================================

public:
Expand All @@ -53,7 +35,10 @@ class Scheduler {
// This is useful if we want to adjust the ratio of driver to process runtime
uint8_t consecutive_quantums_to_run;

Task(const stack_registers& initial_stack_frame, uint8_t initial_priority) :
Task(
const exception_stack_registers& initial_stack_frame,
uint8_t initial_priority
) :
first_stack_frame(initial_stack_frame),
consecutive_quantums_to_run(initial_priority)
{}
Expand All @@ -67,6 +52,7 @@ class Scheduler {
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();
Expand Down
18 changes: 18 additions & 0 deletions include/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,22 @@ using ProcessCallbackPtr = void (*)(int, int);
using ProcessName = etl::string<20>;
enum class FaultType { Usage, Bus, Memory };

struct exception_stack_registers {
unsigned R0{};
unsigned R1{};
unsigned R2{};
unsigned R3{};
unsigned R12{};
unsigned LR{};
unsigned RETURN_ADDR{};
unsigned CTRL{0x01000000};
unsigned FP_REGS[16]{};
unsigned FPSCR{};

// diagram: https://shorturl.at/85lyY
unsigned RESERVED_FOR_STACK_ALIGNMENT[2]{};

exception_stack_registers(unsigned return_addr) : RETURN_ADDR(return_addr) {}
};

} // namespace edge
25 changes: 18 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <stdbool.h>
#include <stdio.h>

void task1(void)
void exception_task(void)
{
auto trigger_faults = []() {
// Usage
Expand All @@ -19,8 +19,6 @@ void task1(void)
};

using namespace edge::userlib;
using namespace edge::drivers;

static void (*fault_handler)(edge::FaultType) = [](edge::FaultType type) {
switch (type) {
case edge::FaultType::Usage:
Expand All @@ -35,6 +33,22 @@ void task1(void)
}
};

set_fault_handler(fault_handler);

trigger_faults();

set_led(2, 2, true);

while (1) {
yield();
}
}

void task1(void)
{
using namespace edge::userlib;
using namespace edge::drivers;

static void (*on_button_press)(ButtonType, ButtonState) = [](ButtonType type,
ButtonState state) {
if (state == ButtonState::DOWN) {
Expand All @@ -48,10 +62,6 @@ void task1(void)
get_button_pressed(ButtonType::A, on_button_press);
get_button_pressed(ButtonType::B, on_button_press);

set_fault_handler(fault_handler);

trigger_faults();

while (1) {
yield();
}
Expand Down Expand Up @@ -86,6 +96,7 @@ int main(void)

edge::FaultHandler::get();

edge::scheduler.add_task(exception_task);
edge::scheduler.add_task(task0);
edge::scheduler.add_task(task1);

Expand Down
9 changes: 5 additions & 4 deletions src/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void Scheduler::start_scheduler()
void Scheduler::add_task(void (*function)(void), uint8_t priority)
{
task_stack.emplace_back(
stack_registers{reinterpret_cast<unsigned>(function)}, priority
exception_stack_registers{reinterpret_cast<unsigned>(function)}, priority
);
}

Expand Down Expand Up @@ -144,12 +144,13 @@ void Scheduler::yield_current_task()
// This stack frame, originally created by the exception handler, will be popped
// by restore()
t.stack_ptr_loc = (unsigned*)__get_PSP();
auto stored_registers = reinterpret_cast<stack_registers*>(t.stack_ptr_loc);
auto stored_registers =
reinterpret_cast<exception_stack_registers*>(t.stack_ptr_loc);

// "Push" registers, create a fake stack frame
// This will be popped by the exception handler
t.stack_ptr_loc -= (sizeof(stack_registers) / sizeof(unsigned));
auto new_registers = reinterpret_cast<stack_registers*>(t.stack_ptr_loc);
t.stack_ptr_loc -= (sizeof(exception_stack_registers) / sizeof(unsigned));
auto new_registers = reinterpret_cast<exception_stack_registers*>(t.stack_ptr_loc);
new_registers->R0 = static_cast<unsigned>(arg1);
new_registers->R1 = static_cast<unsigned>(arg2);

Expand Down
61 changes: 31 additions & 30 deletions src/svc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,54 @@

namespace edge {

// TODO: replace uint32_t* stack_ptr with an actual structure

void handle_yield()
{
scheduler.yield_current_task();
}

void handle_change_priority(uint32_t* stack_ptr)
void handle_change_priority(exception_stack_registers* stack_regs)
{
scheduler.change_current_task_priority(stack_ptr[0]);
scheduler.change_current_task_priority(stack_regs->R0);
}

etl::optional<int> handle_driver_command(uint32_t* stack_ptr)
etl::optional<int> handle_driver_command(exception_stack_registers* stack_regs)
{
auto type = static_cast<drivers::DriverCommand>(stack_ptr[0]);
return drivers::handle_command(type, stack_ptr[1], stack_ptr[2], stack_ptr[3]);
auto type = static_cast<drivers::DriverCommand>(stack_regs->R0);
return drivers::handle_command(
type, stack_regs->R1, stack_regs->R2, stack_regs->R3
);
}

void handle_driver_subscribe(uint32_t* stack_ptr)
void handle_driver_subscribe(exception_stack_registers* stack_regs)
{
auto type = static_cast<drivers::DriverSubscribe>(stack_ptr[0]);
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_ptr[1]);
int arg1 = stack_ptr[2];
int arg2 = stack_ptr[3];
auto type = static_cast<drivers::DriverSubscribe>(stack_regs->R0);
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_regs->R1);
int arg1 = stack_regs->R2;
int arg2 = stack_regs->R3;
return drivers::handle_subscribe(
type, callback, arg1, arg2, scheduler.get_current_task()
);
}

void handle_set_fault_handler(uint32_t* stack_ptr)
void handle_set_fault_handler(exception_stack_registers* stack_regs)
{
uint32_t current_task_id = scheduler.get_current_task();
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_ptr[0]);
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_regs->R0);
FaultHandler::get().set_fault_callback(current_task_id, callback);
}

void handle_ipc(uint32_t* stack_ptr)
void handle_ipc(exception_stack_registers* stack_regs)
{
auto type = static_cast<IPCCommandType>(stack_ptr[0]);
auto name = reinterpret_cast<const char*>(stack_ptr[1]);
auto type = static_cast<IPCCommandType>(stack_regs->R0);
auto name = reinterpret_cast<const char*>(stack_regs->R1);
etl::string<20> name_str{name};

if (type == IPCCommandType::SEND) [[likely]] {
auto message = static_cast<int>(stack_ptr[2]);
auto message = static_cast<int>(stack_regs->R2);
IPCManager::get().send_message(name_str, message);
}
else if (type == IPCCommandType::REGISTER) {
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_ptr[2]);
auto callback = reinterpret_cast<ProcessCallbackPtr>(stack_regs->R2);
IPCManager::get().register_callback(
scheduler.get_current_task(), name_str, callback
);
Expand All @@ -68,26 +68,27 @@ void handle_ipc(uint32_t* stack_ptr)
}
}

etl::optional<int> handle_call(uint32_t* stack_ptr)
etl::optional<int> handle_call(exception_stack_registers* stack_regs)
{
auto call_type = static_cast<SystemCallType>(((char*)stack_ptr[6])[-2]);
auto call_type =
static_cast<SystemCallType>(((char*)(stack_regs->RETURN_ADDR))[-2]);
switch (call_type) {
case SystemCallType::CHANGE_PRIORITY:
handle_change_priority(stack_ptr);
handle_change_priority(stack_regs);
break;
case SystemCallType::YIELD:
handle_yield();
break;
case SystemCallType::COMMAND:
return handle_driver_command(stack_ptr);
return handle_driver_command(stack_regs);
case SystemCallType::SUBSCRIBE:
handle_driver_subscribe(stack_ptr);
handle_driver_subscribe(stack_regs);
break;
case edge::SystemCallType::IPC:
handle_ipc(stack_ptr);
handle_ipc(stack_regs);
break;
case edge::SystemCallType::SET_FAULT_HANDLER:
handle_set_fault_handler(stack_ptr);
handle_set_fault_handler(stack_regs);
break;
}
return etl::nullopt;
Expand All @@ -102,11 +103,11 @@ __attribute__((used)) void SVC_Handler(void)
has_hit = true;
return;
}
uint32_t* SP_reg;
asm("MRS %0,PSP" : "=r"(SP_reg));
auto ret_opt = handle_call(SP_reg);
exception_stack_registers* stack_regs;
asm("MRS %0,PSP" : "=r"(stack_regs));
auto ret_opt = handle_call(stack_regs);
if (ret_opt) {
SP_reg[0] = *ret_opt;
stack_regs->R0 = *ret_opt;
}
}
}
Expand Down

0 comments on commit 933cf40

Please sign in to comment.