System Calls cleanup, multiple Processes and context switch
[cortex-from-scratch] / ivt.c
diff --git a/ivt.c b/ivt.c
index 9f8e643..2cb86e7 100644 (file)
--- a/ivt.c
+++ b/ivt.c
 #include <lib/stdio.h>
 #include <lib/string.h>
 #include <lib/regfunc.h>
+#include <lib/tinyprintf.h>
 
 /* 
  * These values are pushed on the stack just before
- * entering the ISR. Normally, this would require
- * assembly or inline assembly code. I use a so-called
- * 'naked function' __attribute__ ((interrupt)) which
+ * entering the ISR. I use a so-called
+ * 'naked function' __attribute__ ((naked)) which
  * gives me a little bit more control over the caller
  *
  * The following register are pushed to the stack
@@ -52,7 +52,7 @@ struct interrupt_frame {
        uint32_t lr;
        uint32_t pc;
        uint32_t psr; // N-4
-};
+} frame;
 
 /* 
  * Vector table, each entry contains an interrupt
@@ -63,7 +63,7 @@ struct interrupt_frame {
  * */
 uint32_t __attribute__((aligned(0x100))) ivt[92];
 
-/* Each message corresponds to each and every exception. */
+/* Each message corresponds to an exception in the vector table. */
 char * exception_message(uint8_t intnr) {
 
 char * messages[] = {
@@ -75,6 +75,9 @@ char * messages[] = {
     "BUS FAULT",
     "USAGE FAULT",
     "RESERVED",
+    "RESERVED",
+    "RESERVED",
+    "RESERVED",
     "SVC",
     "DEBUG MONITOR",
     "RESERVED",
@@ -92,30 +95,53 @@ char * messages[] = {
 
 if (intnr < 20) // TODO: strlen
        return messages[intnr];
-       return NULL;
+
+return "UNKNOWN";
+
 }
 
+/* Function to set entries of the interrupt vector table 
+ * */
 void ivt_set_gate(unsigned char num, void * isr(), short pri) {
 
        ivt[num] = (uint32_t) isr;
-       *NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F));
+       //if (num <= 32)
+       //*NVIC_ISER0 = (1 << ((uint32_t)(num) & 0x1F));
        /* TODO: Priorities */
 }
 
 
-/* Dummy interrupt: comment out the comment to use a naked
- * function */
-
-// __attribute__ ((interrupt)) 
-void * dummy_isr(/* struct interrupt_frame * frame */) {
-
-       uint8_t nr = *SCB_VTOR_ST & 0xFF;
+/* Dummy interrupt: shows the saved stack registers and then
+ * halts */
+__attribute__ ((naked)) void * dummy_isr(void) {
+
+       uint32_t * current_sp;
+
+       /* Test whether system call was invoked from supervisor (use MSP) or
+        * user (use PSP) mode */
+       asm volatile (
+       "tst lr, #4" "\n\t"
+       "ite eq" "\n\t"
+       "mrseq %0, msp" "\n\t"
+       "mrsne %0, psp" : "=r" (current_sp));
+
+       memcpy(&frame, current_sp, sizeof(struct interrupt_frame));
+
+       uint8_t nr = *SCB_ICSR & 0xFF;
+       printf("EXCEPTION: %s\n", exception_message(nr));
+       printf("STACKFRAME:\n");
+       printf("R0:%p\n",frame.r0);
+       printf("R1:%p\n",frame.r1);
+       printf("R2:%p\n",frame.r2);
+       printf("R3:%p\n",frame.r3);
+       printf("R12:%p\n",frame.r12);
+       printf("LR:%p\n",frame.lr);
+       printf("PC:%p (<-- last function call)\n",frame.pc);
+       printf("PSR:%p\n",frame.psr);
        
-       cputs("EXCEPTION: ");
-       cputs(exception_message(nr));
-       cputs("\nSYSTEM HALTED\n");
-       
-       for(;;);
+       printf("CPU STATUS:");
+       printf("%x\n", *SCB_CFSR);
+       for(;;); 
 }
 
 /* Initialize interrupt vector  */
@@ -130,15 +156,28 @@ void ivt_init() {
        *  */
        extern void * reset,  * nmi, * hardfault;
 
-       // set dummy handlers 
+       /* set dummy handlers */
        for (int i = 1; i <= 64 ; i++) {
                ivt_set_gate(i, dummy_isr, 0);
        }
 
+
+       /* Enable memory management, bus and usage fault exceptions handlers
+        * If these are not enabled, the processor treats them as a hard
+        * faults. Unpriviliged access will cause a busfault in case no MPU */
+       rsetbit(SCB_SHCSR, 16); // MPU violation
+       rsetbit(SCB_SHCSR, 17); // Bus faults
+       rsetbit(SCB_SHCSR, 18); // Usage faults
+       
+       /* Enable various other faults */
+       // rsetbit(SCB_CCR, 4); // division by zero, (needed if you write a lot
+       // of assembly, otherwise the compiler probably leave these divisions out
+
+
        /* The vector table is intially at 0x0. The vector table can be
         * relocated to other memory locations. We can do this by setting 
         * a register in the NVIC called the vector table offset register */
 
-       regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE);
+       rwrite(SCB_VTOR, (uint32_t) &ivt);
 
 }