aboutsummaryrefslogtreecommitdiff
path: root/src/interrupts
diff options
context:
space:
mode:
Diffstat (limited to 'src/interrupts')
-rw-r--r--src/interrupts/interrupt_vector.S56
-rw-r--r--src/interrupts/interrupts.c135
-rw-r--r--src/interrupts/interrupts.h128
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