1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
4 * 2019/7/20 - ROBIN KRENS
8 * Set up of basic exceptions and interrupts. These interrupts
9 * don't do much, except for halting the system.
10 * ivt_set_gate(interrupt nr, function, priority) can be used
11 * later to define more appropriate handling. See timer (timer.c)
12 * or serial or (uart.c) handling for non-trivial examples.
14 * The actual code is not much, but there are a lot of details
15 * to consider. Besides that, in case more control is desired over
16 * entering and exiting interrupts (what is pushed on the stack)
17 * A so-called naked function can be used. See below for more
27 #include <sys/robsys.h>
30 #include <lib/stdio.h>
31 #include <lib/string.h>
32 #include <lib/regfunc.h>
33 #include <lib/tinyprintf.h>
36 * These values are pushed on the stack just before
37 * entering the ISR. Normally, this would require
38 * assembly or inline assembly code. I use a so-called
39 * 'naked function' __attribute__ ((interrupt)) which
40 * gives me a little bit more control over the caller
42 * The following register are pushed to the stack
46 struct interrupt_frame {
59 * Vector table, each entry contains an interrupt
61 * interrupt vector 1-15: processor exceptions
62 * interrupt vector 16-92: irq0 - irq ..
63 * Vector table needs to be aligned in memory.
65 uint32_t __attribute__((aligned(0x100))) ivt[92];
67 /* Each message corresponds to each and every exception. */
68 char * exception_message(uint8_t intnr) {
97 if (intnr < 20) // TODO: strlen
98 return messages[intnr];
103 void ivt_set_gate(unsigned char num, void * isr(), short pri) {
105 ivt[num] = (uint32_t) isr;
107 // *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F));
108 /* TODO: Priorities */
112 /* Dummy interrupt: comment out the comment to use a naked
115 struct interrupt_frame * frame;
117 //__attribute__ ((interrupt))
118 void * dummy_isr( struct interrupt_frame * f ) {
120 //uint32_t link_register = 0;
121 //asm ("mov %0, #33" : "=r" (lp));
123 /* Check Link Register:
124 * If you ever need to debug these: here are the most common
126 * 0xFFFFFFF1: return to handler mode (nested interrupts
127 * 0xFFFFFFF9: return to thread mode using main stack
128 * 0xFFFFFFFD: return to thread mode using process stack */
129 // asm ("mov %0, lr" : "=r" (link_register));
130 // printf("%x\n", link_register);
133 // asm volatile ("push {r0-r12}");
135 // asm volatile ("tst lr, #4" "\n\t"
137 // "mrseq %0, msp" "\n\t"
138 // "mrsne r0, psp" : "=r" (stack));
140 // printf("STACK: %x, %x, %x, %x, %x", stack[32], stack[28], stack[24], stack[20], stack[16]);
142 // asm volatile ("CPSID f");
144 // uint32_t tmp = args[0];
145 // uint32_t tmp2 = args[1];
146 // printf("%x, %x\n", tmp, tmp2);
147 // uint32_t tmp3 = args[2];
148 // uint32_t tmp4 = args[3];
149 // printf("%x, %x\n", tmp3, tmp4);
151 struct interrupt_frame * frame = (struct interrupt_frame * )kalloc(get_kheap());
152 memcpy(frame, f, sizeof(struct interrupt_frame));
154 uint8_t nr = *SCB_VTOR_ST & 0xFF;
155 printf("EXCEPTION: %s\n", exception_message(nr));
156 printf("STACK TRACE:\n");
157 printf("R0:%p\n",frame->r0);
158 printf("R1:%p\n",frame->r1);
159 printf("R2:%p\n",frame->r2);
160 printf("R3:%p\n",frame->r3);
161 printf("R12:%p\n",frame->r12);
162 printf("LR:%p\n",frame->lr);
163 printf("PC:%p\n",frame->pc);
164 printf("PSR:%p\n",frame->psr);
169 /* Initialize interrupt vector */
172 /* clear entire IVT location in memory */
173 memset(&ivt, 0, (sizeof(uint32_t) * 92));
175 /* The reset, NMI and hardfault handlers are originally
176 * defined in the assembly start up and can be
177 * reused or overwritten.
179 extern void * reset, * nmi, * hardfault;
181 // set dummy handlers
182 for (int i = 1; i <= 64 ; i++) {
183 ivt_set_gate(i, dummy_isr, 0);
186 /* The vector table is intially at 0x0. The vector table can be
187 * relocated to other memory locations. We can do this by setting
188 * a register in the NVIC called the vector table offset register */
190 rwrite(SCB_VTOR, (uint32_t) &ivt);