fe_rtos 0.1.1

A simple OS for Arm Cortex-M CPUs
Documentation
    .syntax unified
    .section .text.asm
    .weak sys_exit
    .weak sys_sleep
    .weak sys_alloc
    .weak sys_dealloc
    .weak sys_block
    .weak sys_task_spawn
    .weak sys_yield
    .weak sys_ipc_publish
    .weak sys_ipc_subscribe
    .weak sys_ipc_unsubscribe
    .weak sys_ipc_get_message
    .weak sys_get_heap_remaining
    .weak sys_interrupt_register
    .global svc_handler
.equ max_svc, 11

///////////////////////////////////////////////////////////////////////////////
// Arm Cortex-M interrupt stack frame order:
// high address: xPSR
//      |         PC
//      |         LR
//      |         R12
//      |         R3
//      |         R2
//      |         R1
//  low address:  R0
///////////////////////////////////////////////////////////////////////////////

    .thumb_func
//Do not overwrite R0-R3 because they hold the syscall params
svc_handler:
    //////////////////////////////
    //Retrieve the syscall number
    //////////////////////////////

    //Find the stacked PC
    //Offest is 24(decimal) + (registers pushed * 4)
    LDR R0, [SP, 0x18]
    //Get the svc instruction
    LDRH R0, [R0, -2]
    //Get the syscall number from the instruction
    BIC R0, R0, 0xFF00

    //////////////////////////////
    //Get the syscall address
    //////////////////////////////

    //Determine if the syscall number is valid
    CMP R0, max_svc
    BGT svc_handler_end

    //If it is valid, grab the address of the function
    ADR R1, svc_addr_table
    LDR R0, [R1, R0, LSL 2]

    //////////////////////////////
    //Fix the stack
    //////////////////////////////
    //The old PC in the ISR stackframe is the new LR in the ISR stackframe
    LDR R1, [SP, 0x18]
    //Setting the LSB of LR to 1 indicates that we are in thumb mode
    ORR R1, R1, 1
    STR R1, [SP, 0x14]

    //The new PC in the ISR stackframe is where we're jumping to
    STR R0, [SP, 0x18]

    .thumb_func
svc_handler_end:
    BX LR

.align 4
svc_addr_table:
    .word sys_exit               // 0
    .word sys_sleep              // 1
    .word sys_alloc              // 2
    .word sys_dealloc            // 3
    .word sys_block              // 4
    .word sys_task_spawn         // 5
    .word sys_yield              // 6
    .word sys_ipc_publish        // 7
    .word sys_ipc_subscribe      // 8
    .word sys_ipc_unsubscribe    // 9
    .word sys_ipc_get_message    // 10
    .word sys_get_heap_remaining // 11
    .word sys_interrupt_register // 12