diff options
author | vetch <vetch97@gmail.com> | 2020-01-04 19:37:32 +0100 |
---|---|---|
committer | vetch <vetch97@gmail.com> | 2020-01-04 19:37:32 +0100 |
commit | 615e3302c9dd358bb64cd56d1f3814ad8d5df84d (patch) | |
tree | 07b0469807eb3bff7ff7d3f3576858642bc66675 /src/interrupts | |
parent | 885a097da42317f48cead2d91c0e0240066943a8 (diff) | |
download | rpi-MMU-example-615e3302c9dd358bb64cd56d1f3814ad8d5df84d.tar.gz rpi-MMU-example-615e3302c9dd358bb64cd56d1f3814ad8d5df84d.zip |
rearranged files, updated makefile
Diffstat (limited to 'src/interrupts')
-rw-r--r-- | src/interrupts/interrupt_vector.S | 56 | ||||
-rw-r--r-- | src/interrupts/interrupts.c | 135 | ||||
-rw-r--r-- | src/interrupts/interrupts.h | 128 |
3 files changed, 319 insertions, 0 deletions
diff --git a/src/interrupts/interrupt_vector.S b/src/interrupts/interrupt_vector.S new file mode 100644 index 0000000..1ec80f7 --- /dev/null +++ b/src/interrupts/interrupt_vector.S @@ -0,0 +1,56 @@ +_interrupt_vectors: + b reset_handler_caller + b undef_handler_caller + b svc_handler_caller + b abort_handler_caller + b abort_handler_caller + b generic_handler_caller + b irq_handler_caller + b fiq_handler_caller + +reset_handler_caller: + ldr sp, =_supervisor_stack_top + ldr r5, =reset_handler + bx r5 + +undef_handler_caller: + ldr sp, =_supervisor_stack_top + ldr r5, =undefined_instruction_vector + bx r5 + +svc_handler_caller: + ldr sp, =_supervisor_stack_top + push {r0-r12, lr} + mov r0, sp + ldr r5, =supervisor_call_handler + blx r5 + ldm sp!, {r0-r12, pc} ^ + +abort_handler_caller: + ldr sp, =_supervisor_stack_top + ldr r5, =abort_handler + bx r5 + +generic_handler_caller: + ldr sp, =_supervisor_stack_top + ldr r5, =generic_handler + bx r5 + +irq_handler_caller: + ldr sp, =_irq_stack_top + sub lr, #4 + push {r0-r12, lr} + mov r0, sp + ldr r3, =irq_handler + blx r3 + ldm sp!, {r0-r12, pc} ^ + +fiq_handler_caller: + ldr sp, =_fiq_stack_top + ldr r5, =fiq_handler + bx r5 + +irq: + mov sp, #0x8000 + ldr r5, =abort_handler + subs pc,lr,#4 diff --git a/src/interrupts/interrupts.c b/src/interrupts/interrupts.c new file mode 100644 index 0000000..121d79c --- /dev/null +++ b/src/interrupts/interrupts.c @@ -0,0 +1,135 @@ +#include "io.h" +#include "uart.h" +#include "svc_interface.h" +#include "armclock.h" +#include "scheduler.h" +/** + @brief The undefined instruction interrupt handler +**/ + + +void __attribute__((noreturn)) setup(void); + +// from what I've heard, reset is never used on the Pi; +// in our case it should run once - when stage1 of the kernel +// jumps to stage2 +void reset_handler(void) +{ + setup(); +} + +void undefined_instruction_vector(void) +{ + error("Undefined instruction occured"); +} + +uint32_t supervisor_call_handler(uint32_t regs[14]) +{ + switch(regs[0]) { + case UART_PUTCHAR: + if (putchar_non_blocking(regs[1])) + schedule_wait_for_output(regs, regs[1]); + break; + case UART_GETCHAR: + { + int c; + if ((c = getchar_non_blocking()) == -1) + schedule_wait_for_input(regs); + + regs[0] = c; + break; + } + case UART_WRITE: + error("UART_WRITE not implemented!!!!!"); + break; + default: + // perhaps we should kill the process now? + error("unknown supervisor call type!!!!!"); + } + + return 0; // a dummy value +} + +void abort_handler(void) +{ + // TODO maybe dump registers here? + error("re-entered system due to data/prefetch abort"); +} + +void generic_handler(void) +{ + error("something weird happened"); +} + +void irq_handler(uint32_t regs[14]) +{ + if (armclk_irq_pending()) + { + write_SPSR(PL1_PSR); + asm volatile("mov r0, %[context]\n\r" + "mov lr, %[return_func]\n\r" + "subs pc, lr, #0" :: + [context]"r" (regs), + [return_func]"r" (schedule_save_context) : + "memory"); + } + else if (uart_irq_pending()) + { + if (uart_recv_irq_pending()) + { + uart_clear_recv_irq(); + scheduler_try_input(); + } + if (uart_send_irq_pending()) + { + uart_clear_send_irq(); + scheduler_try_output(); + } + + if (read_SPSR().fields.PSR_MODE_4_0 != MODE_USER) + { + write_SPSR(PL1_PSR); + asm volatile("mov lr, %0\n\r" + "subs pc, lr, #0" :: + "r" (schedule) : "memory"); + } + } + else + error("unknown irq"); + + // important - don't allow this handler to return if irq came from + // PL1 (likely supervisor, because we don't really use system) mode +} + +void fiq_handler(void) +{ + error("fiq happened"); +} + + +/* Here is your interrupt function */ +//void +//__attribute__((interrupt("IRQ"))) +//__attribute__((section(".interrupt_vectors.text"))) +//irq_handler2(void) { +// /* You code goes here */ +//// uart_puts("GOT INTERRUPT!\r\n"); +// +// local_timer_clr_reload_reg_t temp = { .IntClear = 1, .Reload = 1 }; +// QA7->TimerClearReload = temp; // Clear interrupt & reload +//} + +///* here is your main */ +//int enable_timer(void) { +// +// QA7->TimerRouting.Routing = LOCALTIMER_TO_CORE0_IRQ; // Route local timer IRQ to Core0 +// QA7->TimerControlStatus.ReloadValue = 100; // Timer period set +// QA7->TimerControlStatus.TimerEnable = 1; // Timer enabled +// QA7->TimerControlStatus.IntEnable = 1; // Timer IRQ enabled +// QA7->TimerClearReload.IntClear = 1; // Clear interrupt +// QA7->TimerClearReload.Reload = 1; // Reload now +// QA7->Core0TimerIntControl.nCNTPNSIRQ_IRQ = 1; // We are in NS EL1 so enable IRQ to core0 that level +// QA7->Core0TimerIntControl.nCNTPNSIRQ_FIQ = 0; // Make sure FIQ is zero +//// uart_puts("Enabled Timer\r\n"); +// return(0); +//}
\ No newline at end of file diff --git a/src/interrupts/interrupts.h b/src/interrupts/interrupts.h new file mode 100644 index 0000000..e9ade80 --- /dev/null +++ b/src/interrupts/interrupts.h @@ -0,0 +1,128 @@ +#ifndef RPI_MMU_EXAMPLE_INTERRUPTS_H +#define RPI_MMU_EXAMPLE_INTERRUPTS_H + +#include <stdint.h> + + //offset of peripherals+ offset for first addresable register for interupt controller +#define RPI_INTERRUPT_CONTROLLER_BASE ( 0x3F000000UL + 0xB200 ) + +// Bits in the Enable_Basic_IRQs register to enable various interrupts. +// According to the BCM2835 ARM Peripherals manual, section 7.5 */ + +#define RPI_BASIC_ARM_TIMER_IRQ (1 << 0) +#define RPI_BASIC_ARM_MAILBOX_IRQ (1 << 1) +#define RPI_BASIC_ARM_DOORBELL_0_IRQ (1 << 2) +#define RPI_BASIC_ARM_DOORBELL_1_IRQ (1 << 3) +#define RPI_BASIC_GPU_0_HALTED_IRQ (1 << 4) +#define RPI_BASIC_GPU_1_HALTED_IRQ (1 << 5) +#define RPI_BASIC_ACCESS_ERROR_1_IRQ (1 << 6) +#define RPI_BASIC_ACCESS_ERROR_0_IRQ (1 << 7) + +// @brief The interrupt controller memory mapped register set +typedef struct { + volatile uint32_t IRQ_basic_pending; + volatile uint32_t IRQ_pending_1; + volatile uint32_t IRQ_pending_2; + volatile uint32_t FIQ_control; + volatile uint32_t Enable_IRQs_1; + volatile uint32_t Enable_IRQs_2; + volatile uint32_t Enable_Basic_IRQs; + volatile uint32_t Disable_IRQs_1; + volatile uint32_t Disable_IRQs_2; + volatile uint32_t Disable_Basic_IRQs; +} rpi_irq_controller_t; + +extern rpi_irq_controller_t* RPI_GetIrqController(void); + +//TIMER + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER INTERRUPT ROUTING REGISTER - QA7_rev3.4.pdf page 18 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + enum { + LOCALTIMER_TO_CORE0_IRQ = 0, + LOCALTIMER_TO_CORE1_IRQ = 1, + LOCALTIMER_TO_CORE2_IRQ = 2, + LOCALTIMER_TO_CORE3_IRQ = 3, + LOCALTIMER_TO_CORE0_FIQ = 4, + LOCALTIMER_TO_CORE1_FIQ = 5, + LOCALTIMER_TO_CORE2_FIQ = 6, + LOCALTIMER_TO_CORE3_FIQ = 7, + } Routing: 3; // @0-2 Local Timer routing + unsigned unused : 29; // @3-31 + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_int_route_reg_t; + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER CONTROL AND STATUS REGISTER - QA7_rev3.4.pdf page 17 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned ReloadValue : 28; // @0-27 Reload value + unsigned TimerEnable : 1; // @28 Timer enable (1 = enabled) + unsigned IntEnable : 1; // @29 Interrupt enable (1= enabled) + unsigned unused : 1; // @30 Unused + unsigned IntPending : 1; // @31 Timer Interrupt flag (Read-Only) + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_ctrl_status_reg_t; + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER CLEAR AND RELOAD REGISTER - QA7_rev3.4.pdf page 18 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned unused : 30; // @0-29 unused + unsigned Reload : 1; // @30 Local timer-reloaded when written as 1 + unsigned IntClear : 1; // @31 Interrupt flag clear when written as 1 + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_clr_reload_reg_t; + +/*--------------------------------------------------------------------------} +{ GENERIC TIMER INTERRUPT CONTROL REGISTER - QA7_rev3.4.pdf page 13 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned nCNTPSIRQ_IRQ : 1; // @0 Secure physical timer event IRQ enabled, This bit is only valid if bit 4 is clear otherwise it is ignored. + unsigned nCNTPNSIRQ_IRQ : 1; // @1 Non-secure physical timer event IRQ enabled, This bit is only valid if bit 5 is clear otherwise it is ignored + unsigned nCNTHPIRQ_IRQ : 1; // @2 Hypervisor physical timer event IRQ enabled, This bit is only valid if bit 6 is clear otherwise it is ignored + unsigned nCNTVIRQ_IRQ : 1; // @3 Virtual physical timer event IRQ enabled, This bit is only valid if bit 7 is clear otherwise it is ignored + unsigned nCNTPSIRQ_FIQ : 1; // @4 Secure physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (0) + unsigned nCNTPNSIRQ_FIQ : 1; // @5 Non-secure physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (1) + unsigned nCNTHPIRQ_FIQ : 1; // @6 Hypervisor physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (2) + unsigned nCNTVIRQ_FIQ : 1; // @7 Virtual physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (3) + unsigned reserved : 24; // @8-31 reserved + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} generic_timer_int_ctrl_reg_t; + +struct __attribute__((__packed__, aligned(4))) QA7Registers { + local_timer_int_route_reg_t TimerRouting; // 0x24 + uint32_t GPIORouting; // 0x28 + uint32_t AXIOutstandingCounters; // 0x2C + uint32_t AXIOutstandingIrq; // 0x30 + local_timer_ctrl_status_reg_t TimerControlStatus; // 0x34 + local_timer_clr_reload_reg_t TimerClearReload; // 0x38 + uint32_t unused; // 0x3C + generic_timer_int_ctrl_reg_t Core0TimerIntControl; // 0x40 + generic_timer_int_ctrl_reg_t Core1TimerIntControl; // 0x44 + generic_timer_int_ctrl_reg_t Core2TimerIntControl; // 0x48 + generic_timer_int_ctrl_reg_t Core3TimerIntControl; // 0x4C +}; +#define QA7 ((volatile __attribute__((aligned(4))) struct QA7Registers*)(uintptr_t)(0x40000024)) +//40000040 + +int enable_timer(void); +#endif //RPI_MMU_EXAMPLE_INTERRUPTS_H |