timer interrupts enabled
authorClaudio Föllmi <foellmic@student.ethz.ch>
Wed, 4 Sep 2013 23:15:10 +0000 (01:15 +0200)
committerClaudio Föllmi <foellmic@student.ethz.ch>
Wed, 4 Sep 2013 23:15:10 +0000 (01:15 +0200)
fixed interrupt handler writing to trap area for non-trap interrupts
enabled timer interrupts at reasonable intervals (reasonable for -O2 and no caches)
added system call for restoring a context (just for armv7-m, replacing a x86-specific interrupt),
because the ONLY way to restore an IT block is by exiting handler mode (there is literally no other mechanism)
(will only be called if userspace tries to restore a context that was saved by the kernel, and comes from interrupting an IT block or a ldm/stm instruction)

You may want to use -O2 from now on (because we use interrupts, and thrashing is possible)
The compiler we use will probably complain up to 3 times ("unable to find a register to spill in class 'GENERAL_REGS'")
just retry the faulting compile instruction with -O1, and then restart make

15 files changed:
devices/omap/omap44xx_cortex_m3_nvic.dev
include/arch/arm/barrelfish/syscall_arch.h
include/barrelfish_kpi/sys_debug.h
include/barrelfish_kpi/syscalls.h
kernel/arch/armv7-m/exceptions.S
kernel/arch/armv7-m/exec.c
kernel/arch/armv7-m/exn.c
kernel/arch/armv7-m/init.c
kernel/arch/armv7/syscall.c
kernel/include/arch/armv7-m/armv7_syscall.h
kernel/include/arch/armv7-m/exceptions.h
lib/barrelfish/arch/arm/dispatch.c
lib/barrelfish/arch/arm/entry.S
lib/barrelfish/arch/arm/syscall.S
lib/barrelfish/arch/arm/syscalls.c

index e099a07..caafc33 100644 (file)
@@ -39,7 +39,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
     //SysTick registers
     register SYSTICK_CTRL rw addr(base, 0x10) "SysTick control and status register"{
         _               15;
-        countflag       1       "Reads 1 if timer counted to 0 since last read. Clears on read.";
+        countflag       1  rc   "Reads 1 if timer counted to 0 since last read. Clears on read.";
         _               13;
         clksource       1       "clock source: 1 = core clock, 0 = external reference clock";
         tickint         1       "interrupt on counting to 0";
@@ -55,7 +55,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
 
     register SYSTICK_CRTV rw addr(base, 0x18) "SysTick current value register"{
         _               8;
-        current         24       "current counter value, clears on write";
+        current         24  rwc "current counter value, clears on write";
     };
 
 
@@ -63,7 +63,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
         noref           1       "no reference clock provided";
         skew            1       "calibration value not exactly 10ms because of clock frequency";
         _               6;
-        tenms           24       "reload value for 10ms timing. 0 = value not known";
+        tenms           24      "reload value for 10ms timing. 0 = value not known";
     };
     
     
@@ -186,7 +186,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
     }; 
 
 
-   register CFSR rw addr(base, 0xD28) "Configurable Fault Status register"{//write-1-to-clear
+   register CFSR rwc addr(base, 0xD28) "Configurable Fault Status register"{
         _               6;
         divbyzero       1       "attempted division by 0 while div_by_zero enabled.";
         unaligned       1       "attempted unaligned access while unaligned_trp enabled";
@@ -211,7 +211,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
         iaccviol        1       "instruction access violation (such as trying to execute from a XN region). does not set MMAR";
     }; 
 
-   register HFSR rw addr(base, 0xD2C) "Hard Fault Status register"{//write-1-to-clear
+   register HFSR rwc addr(base, 0xD2C) "Hard Fault Status register"{
         debugevt        1       "debug related fault";
         forced          1       "configurable fault triggered but disabled or too low priority";
         _               28;
@@ -219,7 +219,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
         _               1;
     }; 
     
-   register DFSR rw addr(base, 0xD30) "Debug Fault Status register"{//write-1-to-clear
+   register DFSR rwc addr(base, 0xD30) "Debug Fault Status register"{
         _               27;
         external        1       "external debug request flag";
         vcatch          1       "vector catch flag";
@@ -237,7 +237,7 @@ device omap44xx_cortex_m3_nvic msbfirst (addr base)
     }; 
     
     
-   register AFSR rw addr(base, 0xD3C) "Auxiliary Fault Status register"{//write-1-to-clear
+   register AFSR rwc addr(base, 0xD3C) "Auxiliary Fault Status register"{
         impdef          32      "implementation defined. maps directly to AUXFAULT input signals";
     }; 
     
index 5af8cb2..62f566f 100644 (file)
@@ -81,4 +81,11 @@ syscall(uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e,
 #define syscall1(a)                                                     \
     syscallx(sysord(a,1),0,0,0,0,0,0,0,0,0,0,0)
 
+
+#ifdef __ARM_ARCH_7M__  //cortex-m3 on pandaboard
+//add syscall for restoring a context that the dispatcher can not restore by itself
+errval_t sys_resume_context(arch_registers_state_t* registers);
+#endif
+
+
 #endif
index 0d9431e..13809fd 100644 (file)
@@ -29,7 +29,7 @@ enum debug_message {
     DEBUG_GET_TSC_PER_MS,
     DEBUG_GET_APIC_TIMER,
     DEBUG_GET_APIC_TICKS_PER_SEC,
-    DEBUG_FEIGN_FRAME_CAP,
+    DEBUG_FEIGN_FRAME_CAP
 };
 
 #endif //BARRELFISH_KPI_SYS_DEBUG_H
index 965d9cf..4ccb385 100644 (file)
@@ -47,7 +47,14 @@ struct sysret {
 
 /* Architecture-specific syscalls 
  * FIXME: shouldn't these be in an arch-specific header? -AB */
+#ifdef __ARM_ARCH_7M__  //cortex-m3 on pandaboard
+//overwrite unused syscall instead of creating yet another global one
+#define SYSCALL_RESUME_CONTEXT      7     ///< Resume a context that the dispatcher can't
+#else
 #define SYSCALL_X86_FPU_TRAP_ON     7     ///< Turn FPU trap on (x86)
+#endif  //__ARM_ARCH_7M__
+
+
 #define SYSCALL_X86_RELOAD_LDT      8     ///< Reload the LDT register (x86_64)
 
 #define SYSCALL_COUNT               9     ///< Number of syscalls [0..SYSCALL_COUNT - 1]
index 5ffd01b..0ff0e55 100644 (file)
@@ -76,7 +76,7 @@ got_for_handler_mode:
         //
 exceptions_early_init:
         //use SVcall, because this is always enabled and can be triggered by a single instruction
-        //XXX: HACK using the fact that whatever vector table we are currently using, 
+        //XXX: using the fact that whatever vector table we are currently using, 
         //it will be mapped to address 0
         mov            r2, #0                              // base of vectortable, where the handler will be stored
         mov     r0, # ARM_7M_EVECTOR_SVCALL
@@ -114,16 +114,16 @@ exceptions_init:
         ldr     r1, =vectortable
 $exceptions_install_handlers:
         mov     r0, # ARM_7M_EVECTOR_MEM
-        ldr     r1, =generic_irq_handler                //needs work
+        ldr     r1, =pagefault_handler
         bl      exceptions_install_handler
         mov     r0, # ARM_7M_EVECTOR_BUS
-        ldr     r1, =generic_irq_handler               //needs work
+        ldr     r1, =pagefault_handler
         bl      exceptions_install_handler
         mov     r0, # ARM_7M_EVECTOR_SYSTICK
         ldr     r1, =generic_irq_handler
         bl      exceptions_install_handler
         mov     r0, # ARM_7M_EVECTOR_USAGE
-        ldr     r1, =generic_irq_handler              
+        ldr     r1, =usagefault_handler              
         bl      exceptions_install_handler
         mov     r0, # ARM_7M_EVECTOR_SVCALL
         ldr     r1, =swi_handler
@@ -257,13 +257,13 @@ null_handler:
 /*
  * void generic_irq_handler(void)
  *
- * handler for pretty much any IRQ we get, except system calls (as those take arguments)
+ * handler for pretty much any IRQ we get, except system calls (as those take arguments),
+ * and traps (or rather, what the dispatcher would see as traps -- pagefaults, usage faults)
  * checks if we interrupted userspace or kernelspace,
  * reads out IRQ number,
  * calls a handler that does the case distinction in C
  */
 generic_irq_handler:
-    mrs     r0, IPSR            //what IRQ are we currently handling
     and     r1, lr, #8          // r1 is now 0 if we come from handler mode
     cbnz    r1, generic_irq_handler_user //compares without changing condition flags
     
@@ -281,15 +281,75 @@ generic_irq_handler_user:
     cmp     r1, #0
     ITe     eq    
     addeq   r1, r2, #OFFSETOF_DISP_ENABLED_AREA
-    addne   r1, r2, #OFFSETOF_DISP_TRAP_AREA
+    addne   r1, r2, #OFFSETOF_DISP_DISABLED_AREA
     save_context r1, r3, r2                     // r1 = save area
     init_handler_pic_register     //only set after saving context
+    mrs     r0, IPSR            //what IRQ are we currently handling
     ldr     r3, =handle_irq
     bx      r3
 
+/*
+ * void pagefault_handler(void)
+ *
+ * handler just for pagefaults (which in this case are bus faults or mem faults)
+ */
+pagefault_handler:
+    and     r1, lr, #8          // r1 is now 0 if we come from handler mode
+    cbnz    r1, pagefault_handler_user //compares without changing condition flags
+    
+pagefault_handler_kernel:
+    mov     r2, sp          //place where pushed registers start
+    ldr     r1, [sp, #(PC_REG_PUSHED * 4)]   //this should be where the pushed pc ends up
+    ldr     r3, =fatal_kernel_fault
+    bx      r3
+pagefault_handler_user:
+    init_handler_stack
+    get_dispatcher_shared_arm r2
+    mrs     r0, PSP
+    ldr     r0, [r0, #(PC_REG_PUSHED*4)]    // r0 = faulting pc
+    disp_is_disabled r2, r0, r1             // r1 = 1 if disabled, else 0
+    cmp     r1, #0
+    ITe     eq    
+    addeq   r1, r2, #OFFSETOF_DISP_ENABLED_AREA
+    addne   r1, r2, #OFFSETOF_DISP_TRAP_AREA
+    save_context r1, r3, r2                     // r1 = save area
+    mov     r0, r1                 //save area must be first argument
+    init_handler_pic_register     //only set after saving context
+    ldr     r3, =handle_user_page_fault
+    bx      r3
 
-
+/*
+ * void usagefault_handler(void)
+ *
+ * handler just for usagefaults, which can be:
+ *      undefined instruction
+ *      unaligned access
+ *      division by 0
+ */
+usagefault_handler:
+    and     r1, lr, #8          // r1 is now 0 if we come from handler mode
+    cbnz    r1, usagefault_handler_user //compares without changing condition flags
     
+usagefault_handler_kernel:
+    mov     r2, sp          //place where pushed registers start
+    ldr     r1, [sp, #(PC_REG_PUSHED * 4)]   //this should be where the pushed pc ends up
+    ldr     r3, =fatal_kernel_fault
+    bx      r3
+usagefault_handler_user:
+    init_handler_stack
+    get_dispatcher_shared_arm r2
+    mrs     r0, PSP
+    ldr     r0, [r0, #(PC_REG_PUSHED*4)]    // r0 = faulting pc
+    disp_is_disabled r2, r0, r1             // r1 = 1 if disabled, else 0
+    cmp     r1, #0
+    ITe     eq    
+    addeq   r1, r2, #OFFSETOF_DISP_ENABLED_AREA
+    addne   r1, r2, #OFFSETOF_DISP_TRAP_AREA
+    save_context r1, r3, r2                     // r1 = save area
+    mov     r0, r1                 //save area must be first argument
+    init_handler_pic_register     //only set after saving context
+    ldr     r3, =handle_user_undef
+    bx      r3 
     
         //
         // void swi_handler(void)
@@ -325,7 +385,7 @@ swi_user:   //much like generic_irq_handler, but the save area is in r0
     cmp     r1, #0
     ITe     eq    
     addeq   r1, r2, #OFFSETOF_DISP_ENABLED_AREA
-    addne   r1, r2, #OFFSETOF_DISP_TRAP_AREA
+    addne   r1, r2, #OFFSETOF_DISP_DISABLED_AREA
     save_context r1, r3, r2                     // r1 = save area
     mov     r0, r1                              //sys_syscall expects the context to be in r0
     init_handler_pic_register     //only set this after saving context!
index a87e9c8..a8a6a21 100644 (file)
 #include <misc.h>
 #include <barrelfish_kpi/registers_pushed_arm_v7m.h>//for autopushed register access
 
-static arch_registers_state_t upcall_state;
+static arch_registers_state_t upcall_state;//XXX: is this even used??
 
 extern uint32_t ctr;
 
 /*
- * On armv7-m, the registers r0-r3,r12,lr,pc,apsr are popped from the stack
+ * On armv7-m, the registers r0-r3,r12,lr,pc,xpsr are popped from the stack
  * whenever an exception returns -> we copy those values onto the thread mode stack after
  * restoring the others
  */
@@ -61,6 +61,7 @@ void do_resume(uint32_t *regs)
         //should only actually happen when we first execute a new process
     }
     
+
     __asm volatile(
         "mov    r0, %[regs]                         \n\t"  //address where the regs are
         "ldr    r1, [r0, #56]                       \n\t"  //stored stack pointer
@@ -144,7 +145,9 @@ uint32_t ctr=0;
 void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
 {
     ctr++;
+
     state->named.rtls = arch_get_thread_register();
+
     ensure_user_mode_policy(state);
 
     /*
@@ -158,8 +161,21 @@ void __attribute__ ((noreturn)) resume(arch_registers_state_t *state)
 
 void wait_for_interrupt(void)
 {
-    // REVIEW: Timer interrupt could be masked here.
-
+/*XXX: WARNING: the way this is currently implemented, we will probably never wake up
+ *  we are already in handler mode, and the interrupt we are waiting for does not have
+ *  a higher priority, so it will only be taken when we exit -- which is never (I think)
+ *  (was not able to test it with IPIs, but we do stop servicing timer interrupts)
+ *
+ *  Solution: in this function, first increase the priority of IPIs to the maximum
+ *  write a separate handler for IPIs, that first checks where it came from.
+ *      if it came from handler mode, it must have interrupted this wait 
+ *          -> set priority back down again and then handle the interrupt normally 
+ *              (no context save necessary)
+ *      if it came from thread mode, treat it as any other interrupt (context save etc.)
+ *
+ *  always setting the the priority back down will ensure we never interrupt the kernel
+ *  while it is doing actual work
+ */
     __asm volatile(
         "0:                                             \n\t"
         "wfi                                            \n\t"
index d15a87f..907ed60 100644 (file)
 
 //TODO: heteropanda: actually handle the interrupts, instead of aborting
 
-void handle_user_page_fault(lvaddr_t                fault_address,
-                            arch_registers_state_t* save_area)
+/*
+ * Try to find out what address generated page fault, and then tell the dispatcher what
+ * happened. Some faults will not be recoverable (e.g. stack faults), because the 
+ * context has already been lost
+ */
+void handle_user_page_fault(arch_registers_state_t* save_area)
 {
+    lvaddr_t fault_address;//not passed as argument, because there is not just one place to look
+ /*   
+    //print out registers for debugging
+    printf("page fault. registers:\n");
+    for(uint32_t i = 0; i<NUM_REGS; i++){
+        printf("0x%x\n", save_area->regs[i]);
+    }
+    uint32_t regval;
+    __asm volatile ("mrs %[regval], xpsr" : [regval] "=r"(regval));
+    printf("current XPSR register: 0x%x\n", regval);
+    
+    printf("M3 MMU address: 0x%x\n", *((uint32_t*) &mmu));
+    printf("M3 MMU_FAULT_AD register: 0x%x\n", omap44xx_mmu_fault_ad_rd(&mmu));
+    printf("M3 MMU_FAULT_STATUS register: 0x%x\n", omap44xx_mmu_fault_status_rd(&mmu));
+    printf("M3 MMU_FAULT_PC register: 0x%x\n", omap44xx_mmu_fault_pc_rd(&mmu));
+    printf("M3 MMU_IRQSTATUS register: 0x%x\n", omap44xx_mmu_irqstatus_rd(&mmu));
+    
+    printf("ICTR: 0x%x\n", omap44xx_cortex_m3_nvic_ICTR_rd(&nvic));
+    printf("CPUID_BASE: 0x%x\n", omap44xx_cortex_m3_nvic_CPUID_BASE_rd(&nvic));
+    printf("ICSR: 0x%x\n", omap44xx_cortex_m3_nvic_ICSR_rd(&nvic));
+    printf("VTOR: 0x%x\n", omap44xx_cortex_m3_nvic_VTOR_rd(&nvic));
+    printf("AIRCR: 0x%x\n", omap44xx_cortex_m3_nvic_AIRCR_rd(&nvic));
+    printf("CCR: 0x%x\n", omap44xx_cortex_m3_nvic_CCR_rd(&nvic));
+    printf("SHCSR: 0x%x\n", omap44xx_cortex_m3_nvic_SHCSR_rd(&nvic));
+    printf("CFSR: 0x%x\n", omap44xx_cortex_m3_nvic_CFSR_rd(&nvic));
+    printf("BFAR: 0x%x\n", omap44xx_cortex_m3_nvic_BFAR_rd(&nvic));
+    printf("SYSTICK_CTRL: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CTRL_rd(&nvic));
+    printf("SYSTICK_CALV: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CALV_rd(&nvic));
+  */ 
+    if (omap44xx_cortex_m3_nvic_SHCSR_busfaultact_rdf(&nvic)){
+        //triggered by bus fault    
+        if (omap44xx_mmu_irqstatus_rd(&mmu)){
+            //L2 MMU triggered fault: either no valid mapping, or two mappings in TLB
+            //XXX: cachemarker: once we have chaching enabled, this is the place to
+            //look at table entry for special permission bits.
+            
+            //XXX: MMU_FAULT_ADDR register seems to just contain the last address that was
+            //requested. By this time this is probably just a kernelspace address.
+            //I am not sure if the M3 can actually find out what the faulting address really was
+            fault_address = omap44xx_mmu_fault_ad_rd(&mmu);
+        }
+        else{
+            //"regular" bus fault -> look in NVIC entries
+            if (omap44xx_cortex_m3_nvic_CFSR_bfarvalid_rdf(&nvic)){
+                //bus fault address register valid
+                fault_address = omap44xx_cortex_m3_nvic_BFAR_rd(&nvic);
+            }
+            else{
+                //one of the bus faults that do not write the BFAR -> faulting address
+                //literally unknown to system
+                printk(LOG_WARN, "user bus fault with unknown faulting address\n");
+                fault_address = (lvaddr_t) NULL;
+            }
+        }
+    }
+    else{
+        //memory management fault (probably access violation)
+        if (omap44xx_cortex_m3_nvic_CFSR_mmarvalid_rdf(&nvic)){
+            //MMAR contains faulting address
+            fault_address = omap44xx_cortex_m3_nvic_MMAR_rd(&nvic);
+        }
+        else{
+            //MMAR not written. probably executing in noexecute region
+            assert(omap44xx_cortex_m3_nvic_CFSR_iaccviol_rdf(&nvic));
+            //so we can assume the pc caused the fault
+            fault_address = save_area->named.pc;
+        }
+    }
+    
     lvaddr_t handler;
     struct dispatcher_shared_arm *disp = get_dispatcher_shared_arm(dcb_current->disp);
     uintptr_t saved_pc = save_area->named.pc;
@@ -58,21 +131,17 @@ void handle_user_page_fault(lvaddr_t                fault_address,
         dispatch(schedule());
     }
     else {
-        //
         // Upcall to dispatcher
-        //
-        // NB System might be cleaner with a prototype
-        // dispatch context that has R0-R3 to be overwritten
-        // plus initial stack, thread, and gic registers. Could do
-        // a faster resume_for_upcall().
-        //
+
 
         struct dispatcher_shared_generic *disp_gen =
             get_dispatcher_shared_generic(dcb_current->disp);
 
         union registers_arm resume_area;
 
-        //resume_area.named.xpsr = ?? //since the mode is not encoded in here, we can probably just ignore this
+        //make sure we do not accidentaly create an IT block when upcalling
+        resume_area.named.cpsr = 0; 
+
         resume_area.named.pc   = handler;
         resume_area.named.r0   = disp_gen->udisp;
         resume_area.named.r1   = fault_address;
@@ -80,8 +149,11 @@ void handle_user_page_fault(lvaddr_t                fault_address,
         resume_area.named.r3   = saved_pc;
         resume_area.named.rtls = disp_gen->udisp;
         resume_area.named.r10  = disp->got_base;
-
-        // SP is set by handler routine.
+        
+        //we need some temporary stack to exit handler mode. memory in userspace would be
+        //better, but for the moment we can use this temporary region
+        resume_area.named.stack   = (uint32_t) &irq_save_pushed_area_top;
+        
 
         // Upcall user to save area
         disp->d.disabled = true;
@@ -89,9 +161,13 @@ void handle_user_page_fault(lvaddr_t                fault_address,
     }
 }
 
-void handle_user_undef(lvaddr_t fault_address,
-                       arch_registers_state_t* save_area)
+
+/*
+ * \brief handles undefined instructions, unaligned accesses and division by 0
+ */
+void handle_user_undef(arch_registers_state_t* save_area)
 {
+    lvaddr_t fault_address = save_area->named.pc;//not passed as argument
     union registers_arm resume_area;
 
     struct dispatcher_shared_arm *disp = get_dispatcher_shared_arm(dcb_current->disp);
@@ -101,20 +177,22 @@ void handle_user_undef(lvaddr_t fault_address,
 
     assert(dcb_current->disp_cte.cap.type == ObjType_Frame);
     if (disabled) {
-        //        assert(save_area == &disp->trap_save_area);
+        assert(save_area == &disp->trap_save_area);
     }
     else {
         assert(save_area == &disp->enabled_save_area);
     }
 
-    printk(LOG_WARN, "user undef fault%s in '%.*s': IP %" PRIuPTR "\n",
+    printk(LOG_WARN, "user usage fault%s in '%.*s': IP %" PRIuPTR "\n",
            disabled ? " WHILE DISABLED" : "", DISP_NAME_LEN,
            disp->d.name, fault_address);
 
     struct dispatcher_shared_generic *disp_gen =
         get_dispatcher_shared_generic(dcb_current->disp);
-
-    //resume_area.named.xpsr = ?? //since the mode is not encoded in here, we can probably just ignore this
+        
+        
+    //make sure we do not accidentaly create an IT block when upcalling
+    resume_area.named.cpsr = 0;
     resume_area.named.pc   = disp->d.dispatcher_trap;
     resume_area.named.r0   = disp_gen->udisp;
     resume_area.named.r1   = ARM_7M_EVECTOR_USAGE;
@@ -123,6 +201,10 @@ void handle_user_undef(lvaddr_t fault_address,
     resume_area.named.rtls = disp_gen->udisp;
     resume_area.named.r10  = disp->got_base;
 
+    //we need some temporary stack to exit handler mode. memory in userspace would be
+    //better, but for the moment we can use this temporary region
+    resume_area.named.stack   = (uint32_t) &irq_save_pushed_area_top;
+
     // Upcall user to save area
     disp->d.disabled = true;
     resume(&resume_area);
@@ -149,6 +231,7 @@ static int32_t bkpt_decode(lvaddr_t fault_address)
 void fatal_kernel_fault(uint32_t evector, lvaddr_t address, arch_registers_state_t* save_area
     )
 {
+//TODO: heteropanda: clean this up and print something sensible here
     int i;
     printk(LOG_PANIC, "Kernel fault at %08"PRIxLVADDR
                       " vector %08"PRIx32"\n\n", address, evector);
@@ -185,23 +268,23 @@ void fatal_kernel_fault(uint32_t evector, lvaddr_t address, arch_registers_state
            local_phys_to_mem((uint32_t)&kernel_first_byte) + 0x100000);
 
 
-    printf("Error registers:\n");
-    printf("M3 MMU address: 0x%x\n", *((uint32_t*) &mmu));
-    printf("M3 MMU_FAULT_AD register: 0x%x\n", omap44xx_mmu_fault_ad_rd(&mmu));
-    printf("M3 MMU_FAULT_STATUS register: 0x%x\n", omap44xx_mmu_fault_status_rd(&mmu));
-    printf("M3 MMU_IRQSTATUS register: 0x%x\n", omap44xx_mmu_irqstatus_rd(&mmu));
+    printk(LOG_PANIC,"Error registers:\n");
+    printk(LOG_PANIC,"M3 MMU address: 0x%x\n", *((uint32_t*) &mmu));
+    printk(LOG_PANIC,"M3 MMU_FAULT_AD register: 0x%x\n", omap44xx_mmu_fault_ad_rd(&mmu));
+    printk(LOG_PANIC,"M3 MMU_FAULT_STATUS register: 0x%x\n", omap44xx_mmu_fault_status_rd(&mmu));
+    printk(LOG_PANIC,"M3 MMU_IRQSTATUS register: 0x%x\n", omap44xx_mmu_irqstatus_rd(&mmu));
     
-    printf("ICTR: 0x%x\n", omap44xx_cortex_m3_nvic_ICTR_rd(&nvic));
-    printf("CPUID_BASE: 0x%x\n", omap44xx_cortex_m3_nvic_CPUID_BASE_rd(&nvic));
-    printf("ICSR: 0x%x\n", omap44xx_cortex_m3_nvic_ICSR_rd(&nvic));
-    printf("VTOR: 0x%x\n", omap44xx_cortex_m3_nvic_VTOR_rd(&nvic));
-    printf("AIRCR: 0x%x\n", omap44xx_cortex_m3_nvic_AIRCR_rd(&nvic));
-    printf("CCR: 0x%x\n", omap44xx_cortex_m3_nvic_CCR_rd(&nvic));
-    printf("SHCSR: 0x%x\n", omap44xx_cortex_m3_nvic_SHCSR_rd(&nvic));
-    printf("CFSR: 0x%x\n", omap44xx_cortex_m3_nvic_CFSR_rd(&nvic));
-    printf("BFAR: 0x%x\n", omap44xx_cortex_m3_nvic_BFAR_rd(&nvic));
-    printf("SYSTICK_CTRL: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CTRL_rd(&nvic));
-    printf("SYSTICK_CALV: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CALV_rd(&nvic));
+    printk(LOG_PANIC,"ICTR: 0x%x\n", omap44xx_cortex_m3_nvic_ICTR_rd(&nvic));
+    printk(LOG_PANIC,"CPUID_BASE: 0x%x\n", omap44xx_cortex_m3_nvic_CPUID_BASE_rd(&nvic));
+    printk(LOG_PANIC,"ICSR: 0x%x\n", omap44xx_cortex_m3_nvic_ICSR_rd(&nvic));
+    printk(LOG_PANIC,"VTOR: 0x%x\n", omap44xx_cortex_m3_nvic_VTOR_rd(&nvic));
+    printk(LOG_PANIC,"AIRCR: 0x%x\n", omap44xx_cortex_m3_nvic_AIRCR_rd(&nvic));
+    printk(LOG_PANIC,"CCR: 0x%x\n", omap44xx_cortex_m3_nvic_CCR_rd(&nvic));
+    printk(LOG_PANIC,"SHCSR: 0x%x\n", omap44xx_cortex_m3_nvic_SHCSR_rd(&nvic));
+    printk(LOG_PANIC,"CFSR: 0x%x\n", omap44xx_cortex_m3_nvic_CFSR_rd(&nvic));
+    printk(LOG_PANIC,"BFAR: 0x%x\n", omap44xx_cortex_m3_nvic_BFAR_rd(&nvic));
+    printk(LOG_PANIC,"SYSTICK_CTRL: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CTRL_rd(&nvic));
+    printk(LOG_PANIC,"SYSTICK_CALV: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CALV_rd(&nvic));
 
     switch (evector) {
         case ARM_7M_EVECTOR_USAGE:
@@ -228,12 +311,13 @@ void fatal_kernel_fault(uint32_t evector, lvaddr_t address, arch_registers_state
  */
 void handle_irq(uint32_t irq, arch_registers_state_t* save_area)
 {
+    /*
     printf("handle_irq: registers:\n");//dump content for debugging reasons
     for(uint32_t i = 0; i<NUM_REGS; i++){
         printf("0x%x\n", save_area->regs[i]);
-    }
-    uintptr_t fault_pc = save_area->named.pc;//read faulting pc from pushed context
+    }*/
     
+  /*  
     uint32_t regval;
     __asm volatile ("mrs %[regval], xpsr" : [regval] "=r"(regval));
     printf("current XPSR register: 0x%x\n", regval);
@@ -255,6 +339,8 @@ void handle_irq(uint32_t irq, arch_registers_state_t* save_area)
     printf("BFAR: 0x%x\n", omap44xx_cortex_m3_nvic_BFAR_rd(&nvic));
     printf("SYSTICK_CTRL: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CTRL_rd(&nvic));
     printf("SYSTICK_CALV: 0x%x\n", omap44xx_cortex_m3_nvic_SYSTICK_CALV_rd(&nvic));
+    */
+    uintptr_t fault_pc = save_area->named.pc;//read faulting pc from pushed context
     
     debug(SUBSYS_DISPATCH, "IRQ %"PRIu32" while %s\n", irq,
           dcb_current ? (dcb_current->disabled ? "disabled": "enabled") : "in kernel");
@@ -279,11 +365,12 @@ void handle_irq(uint32_t irq, arch_registers_state_t* save_area)
     //TODO: heteropanda: make a case distinction on the type of interrupt, and  
     //actually handle it
 
-    if (0) {//TODO: heteropanda: should be "if timer interrupt"
-        // Timer interrupt, pit_handle_irq acks it at the timer.
+    if (irq == ARM_7M_EVECTOR_SYSTICK) {
+        // Timer interrupt
         assert(kernel_ticks_enabled);
         kernel_now += kernel_timeslice;
         wakeup_check(kernel_now);
+        printf(".");//to see how many we get & their distribution, without spamming lines
         dispatch(schedule());
     }
     else {
index b1f3be4..c9893d3 100644 (file)
@@ -121,8 +121,6 @@ static void  __attribute__ ((noinline,noreturn)) text_init(void)
         paging_arm_reset(PHYS_MEMORY_START, 0x40000000);
     }
 
-    exceptions_init();
-
 
     //printf("startup_early\n");
     kernel_startup_early();
@@ -163,7 +161,10 @@ static void  __attribute__ ((noinline,noreturn)) text_init(void)
     
     nvic_init();
     printf("nvic_init done\n");
-    systick_init(0x10000);//TODO: heteropanda: find out what cycle count to use here
+    //XXX: cachemarker: these counts are intended for no caching, adjust if we have caching
+    //systick_init(0xFFFFFF);//maximum value
+    //systick_init(0x0AC000);//absolute minimum for -O2: very little progress and much thrashing
+    systick_init(0x0C0000);//reasonable: many interrupts, no thrashing (with -O2)
     printf("systick_init done\n");
     
 
@@ -196,7 +197,8 @@ void  __attribute__ ((noinline,noreturn)) text_init_continued(void){
     
     exceptions_init();//set up proper exception handlers in the relocated vectortable
     
-    
+    printf("starting SysTick timer\n");
+    systick_start();
     arm_kernel_startup();
 }
 
index 4fa5034..8b069f6 100644 (file)
 #include <barrelfish_kpi/syscalls.h>
 #include <barrelfish_kpi/sys_debug.h>
 
-#include <arch/armv7/arm_hal.h>
-#include <arch/armv7/start_aps.h>
-#include <arch/armv7/irq.h>
+#include <arm_hal.h>
+#include <irq.h>
 
 #include <paging_kernel_arch.h>
 #include <dispatch.h>
 #include <exec.h>
 #include <stdio.h>
 #include <syscall.h>
-#include <arch/armv7/armv7_syscall.h>
-#include <arch/armv7/start_aps.h>
+#include <armv7_syscall.h>
+#include <start_aps.h>
 
 __attribute__((noreturn)) void sys_syscall_kernel(void);
 __attribute__((noreturn)) void sys_syscall(arch_registers_state_t* context);
@@ -751,6 +750,14 @@ void sys_syscall(arch_registers_state_t* context)
                 r = handle_debug_syscall(sa->arg1);
             }
             break;
+            
+#ifdef  __ARM_ARCH_7M__
+    //help the dispatcher resume a context that can not be restored whithout a mode change
+        case SYSCALL_RESUME_CONTEXT:
+            if (argc == 2)
+                r.error = sys_resume_context((arch_registers_state_t*) sa->arg1);
+            break;
+#endif  //__ARM_ARCH_7M__
 
         default:
             panic("Illegal syscall");
@@ -769,3 +776,35 @@ void sys_syscall(arch_registers_state_t* context)
     resume(context);
 }
 
+#ifdef __ARM_ARCH_7M__    //armv7-m: cortex-m3 on pandaboard
+/*
+    needed because to resume an interrupted IT block, there literally is only one way:
+    exiting handler mode, restoring the context
+    if the dispatcher has to restore a context with IT-bits set, it can only do so with help
+    from the kernel. 
+*/
+errval_t __attribute__ ((noreturn)) sys_resume_context(arch_registers_state_t* registers){
+    debug(SUBSYS_SYSCALL, "restoring context for dispatcher\n");
+    //because we come from a syscall, r9 does not yet point to current dispatcher.
+    //the context we restore probably has the right one, exept if it is in systemcall
+    //related code (e.g. restoring registers after a syscall)
+    
+    //we want the correct dispatcher, because we want to set disabled = 0
+    //we can not do that in the calling code, because then the act of calling us
+    //would set the enabled area (i.e. it could be restored which we don't want)
+    struct dispatcher_shared_generic *disp_gen
+        = get_dispatcher_shared_generic(dcb_current->disp);//find the correct current dispatcher
+    
+    
+    //resume looks at our value of the rtls register, so we need to set it
+    arch_set_thread_register(disp_gen->udisp);
+    
+    //set dispatcher->disabled = 0, because the resume code would also do that
+    disp_gen->disabled = 0;
+    
+    //((struct dispatcher_shared_generic*) registers->named.rtls)->disabled = 0;
+
+    resume(registers);
+}
+#endif //__ARM_ARCH_7M__
+
index ea432ce..70a3178 100644 (file)
 struct sysret sys_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
                                      genvaddr_t entry);
 
+
+//needed because to resume an interrupted IT block, there literally is only one way:
+//exiting handler mode, restoring the context
+//if the dispatcher has to restore a context with IT-bits set, it can only do so with help
+//from the kernel. 
+//XXX: registers is an area in the userspace of the currently executing process,
+//it is NOT the set of arguments given to the syscall
+errval_t sys_resume_context(arch_registers_state_t* registers);
+
 #endif // ARMV7_SYSCALL_H
index dd28f50..deeea3c 100644 (file)
@@ -48,15 +48,13 @@ void exceptions_init(void);
 /**
  * Handle page fault in user-mode process.
  */
-void handle_user_page_fault(lvaddr_t                fault_address,
-                            arch_registers_state_t* saved_context)
+void handle_user_page_fault(arch_registers_state_t* saved_context)
     __attribute__((noreturn));
 
 /**
  * Handle undefined instruction fault in user-mode process.
  */
-void handle_user_undef(lvaddr_t                fault_address,
-                       arch_registers_state_t* saved_context)
+void handle_user_undef(arch_registers_state_t* saved_context)
     __attribute__((noreturn));
 
 /**
index 849555c..4a0b196 100644 (file)
@@ -18,6 +18,7 @@
 #include <barrelfish/syscalls.h>
 #include <barrelfish/static_assert.h>
 #include "threads_priv.h"
+#include <stdio.h>//for debugging printf
 
 #include <asmoffsets.h>
 #ifndef OFFSETOF_DISP_DISABLED
@@ -68,17 +69,35 @@ disp_resume_context(struct dispatcher_shared_generic *disp, uint32_t *regs)
         "    mov     r0, r0          ; nop                              \n\t"
                   );
 #else       //use pure thumb2
-//we can not use ldm in quite the same way,
-//so we have to restore some registers one by one
 
-//to restore both a general-purpose register AND the pc, we need them to be adjacent in memory
-//since this is normally not the case and we can not 
-//change the data structure we are reading from,
-//we first push them on the restored stack
+#ifdef __ARM_ARCH_7M__  //cortex-m3 on pandaboard
+    //if the context is an interrupted IT-block, we can not restore that ourselves
+    //(because we can not change the epsr)
+    //so we have to ask the kernel to do it for us.
+    //can only happen if the context had originally been saved by the kernel
+    if (regs[CPSR_REG] & 0x0600FC00){//the IPI/IT bits are set
+        //ask the kernel to resume the context for us
+        sys_resume_context((arch_registers_state_t*) regs);
+        printf("disp_resume_context is returning\n");
+        return;//do not resume it a second time in assembly!
+    }
+#endif //__ARM_ARCH_7M__
+
+    //we can not use ldm in quite the same way,
+    //so we have to restore some registers one by one
+
+    //to restore both a general-purpose register AND the pc, we need them to be adjacent
+    //in memory since this is normally not the case and we can not 
+    //change the data structure we are reading from,
+    //we first push them on the restored stack
     __asm volatile(
-        /* Re-enable dispatcher */
-        "    mov     r2, #0                                             \n\t"
-        "    str     r2, [r0, # " XTR(OFFSETOF_DISP_DISABLED) "]        \n\t"
+        /* push the regs pointer, because we can not guarantee that it will not be clobbered*/
+        "    push    {%[regs]}                                           \n\t"
+        /* Re-enable dispatcher (using regs as temp, because we know it is not disp) */
+        "    mov     %[regs], #0                                         \n\t"
+        "    str     %[regs], [%[disp], # " XTR(OFFSETOF_DISP_DISABLED)"]\n\t"
+        //put regs into r1, so it mirrors the function parameter order
+        "    pop     {r1}                                               \n\t"
         //restore sp and lr first, because they can not be used with ldr and need a temp
         "    ldr     r0,  [r1, #(" XTR(SP_REG) "*4)]                    \n\t"//read sp
         "    mov     sp,  r0                                            \n\t"
@@ -110,10 +129,11 @@ disp_resume_context(struct dispatcher_shared_generic *disp, uint32_t *regs)
         "    pop     {r1, pc}                                           \n\t"
         "disp_resume_context_epilog:                                    \n\t"
         "    nop                                                        \n\t"
-        );
+        :: [disp] "r" (disp), [regs] "r" (regs));
 #endif //defined(__thumb2__)
 }
 
+
 static void __attribute__((naked))
 disp_save_context(uint32_t *regs)
 {
index 06578b8..31895ac 100644 (file)
        .extern disp_run, disp_pagefault, disp_pagefault_disabled, disp_trap
        .globl run_entry, pagefault_entry, disabled_pagefault_entry, trap_entry
 
-/*
-heteropanda: since thumb2 has a shorter branch range, I had to do long calls.
-   for some reason, putting the branches in a macro did not compile, so 
-   I put in case distinctions every time we branch (which is admittedly ugly)
-*/
+//since thumb2 has a shorter branch range and can not directly load values into
+//high registers, we have to clobber one of the registers for that. 
 
 .macro init_sp offset
 #ifndef __thumb2__
index 1a771dd..d4733b0 100644 (file)
@@ -65,7 +65,7 @@ swi_done:
         str     r1, [r3, #4]
         pop {r11}
 
-        pop {r3} // Using r3 to tempararily hold the value of sp register
+        pop {r3} // Using r3 to temporarily hold the value of sp register
                  // Warning: Assuming that clobbering r3 is OK!
         pop {lr} // Return address where we have to return
         mov sp, r3  // Restoring sp from r3 now.
index 217c8d2..36b3708 100644 (file)
@@ -34,3 +34,11 @@ errval_t sys_yield(capaddr_t target)
     STATIC_ASSERT_SIZEOF(target, sizeof(uintptr_t));
     return syscall2(SYSCALL_YIELD, (uintptr_t) target).error;
 }
+
+
+#ifdef __ARM_ARCH_7M__  //cortex-m3 on pandaboard
+//add syscall for restoring a context that the dispatcher can not restore by itself
+errval_t sys_resume_context(arch_registers_state_t* registers){
+    return syscall2(SYSCALL_RESUME_CONTEXT, (uintptr_t) registers).error;
+}
+#endif