ARM Cortex A9启动代码和中断设置

时间:2016-10-08 01:33:33

标签: arm interrupt cortex-a gem5

我尝试以裸机方式编程Cortex-A9。我使用了'#hello world'代码来自: https://github.com/tukl-msd/gem5.bare-metal有效。但是,我无法让中断工作。当我用中断创建中断时,例如#47我的软件没有跳过ISR功能。我错过了什么?我还需要做一些初始化吗?

启动代码:

.section INTERRUPT_VECTOR, "x"
.global _Reset
_Reset:
    B Reset_Handler /* Reset */
    B .             /* Undefined */
    B .             /* SWI */
    B .             /* Prefetch Abort */
    B .             /* Data Abort */
    B .             /* reserved */
    B irq_handler   /* IRQ */
    B irq_handler   /* FIQ */

// Some Definitions for GIC:
.equ GIC_DIST, 0x10041000
.equ GIC_CPU , 0x10040000

// GIC Definitions for CPU interface
.equ ICCICR  , 0x00
.equ ICCPMR  , 0x04
.equ ICCEOIR , 0x10
.equ ICCIAR  , 0x0C

// GIC Definitions for Distributor interface
.equ ICDDCR  , 0x00
.equ ICDISER , 0x100
.equ ICDIPTR , 0x800

// Other Definitions
.equ USR_MODE , 0x10

GIC_dist_base : .word 0 // address of GIC distributor
GIC_cpu_base  : .word 0 // address of GIC CPU interface


Reset_Handler:
    LDR sp, =stack_top

    // Enable Interrupts on CPU Side:
    MRS r1, cpsr        // get the cpsr. 
    BIC r1, r1, #0x80   // enable IRQ (ORR to disable). 
    MSR cpsr_c, r1      // copy it back, control field bit update.

    // Configure GIC:
    BL IC_init

    // Branch to C code
    BL main
    B .

// Initialize GIC
.global GIC_init
IC_init:
    stmfd sp!,{lr}
    // Read GIC base from Configuration Base Address Register
    // And use it to initialize GIC_dist_base and GIC_cpu_base
    //mrc p15, 4, r0, c15, c0, 0
    //add r2, r0, #GIC_DIST // Calculate address
    ldr r2, =GIC_DIST
    ldr r1, =GIC_dist_base
    str r2,[r1] // Store address of GIC distributor
    //add r2, r0, #GIC_CPU // Calculate address
    ldr r2, =GIC_CPU
    ldr r1, =GIC_cpu_base
    str r2,[r1] // Store address of GIC CPU interface

    // Register (ICCPMR) to enable interrutps of all priorities
    ldr r1,=0xFFFF
    ldr r2,=GIC_dist_base
    str r1,[r2,#ICCPMR]

    // Set the enable bit in the CPU interface control register
    // ICCICR, allowing CPU(s) to receive interrupts
    mov r1,#1
    str r1,[r2,#ICCICR]

    // Set the enable bit in the distributor control register
    // ICDDCR, allowing interrpupts to be generated
    ldr r2,=GIC_dist_base
    ldr r2,[r2] // Nase address of distributor
    mov r1, #1
    str r1,[r2,#ICDDCR]
    ldmfd sp!,{pc}

//config_interrupt (int ID , int CPU);
.global config_interrupt
config_interrupt:
    stmfd sp!,{r4-r5, lr}

    // Cinfigure the distributor interrupt set-enable registers (ICDISERn)
    // enable the intterupt
    // reg_offset = (M/32)*4 (shift and clear some bits)
    // value = 1 << (N mod 32);
    ldr r2,=GIC_dist_base
    ldr r2,[r2] // Read GIC distributor base address
    add r2,r2,#ICDISER // r2 <- base address of ICDSER regs
    lsr r4,r0,#3 // clculate reg_offset
    bic r4,r4,#3 // r4 <- reg_offset
    add r4,r2,r4 // r4 <- address of ICDISERn

    // Create a bit mask
    and r2,r0,#0x1F // r2 <- N mod 32
    mov r5,#1 // need to set one bit
    lsl r2,r5,r2 // r2 <- value

    // Using address in r4 and value in r2 to set the correct bit in the GIC register
    ldr r3,[r4] // read ICDISERn
    orr r3, r3, r2 // set the enable bit
    str r3,[r4]  // store the new register value

    // Configure the distributor interrupt processor targets register (ICDIPTRn)
    // select target CPU(s)
    // reg_offset = (N/4)*4 (clear 2 bottom bits)
    // index = N mod 4;
    ldr r2,=GIC_dist_base
    ldr r2,[r2] // Read GIC distributor base address
    add r2,r2, #ICDIPTR // base address of ICDIPTR regs
    bic r4,r0,#3 // r4 <- reg_offset
    add r4,r2,r4 // r4 <- address of ICDIPTRn

    // Get the address of th ebyte wihtih ICDIPTRn
    and r2,r0,#0x3 // r2 <- index
    add r4,r2,r4 // r4 <- byte address to be set
    strb r1,[r4]

    ldmfd sp!, {r4-r5, lr}

// int get_inLerrupt_number();
// Get the interrupt ID for the current interrupt. This should be called al the
// beginning of ISR. It also changes the state of the interrupt from pending to
// active, which helps to prevent other CPUs from trying to handle it.
.global get_interrupt_number
get_intterrupt_number:
    // Read the JCCIAR from the CPU Interface
    ldr r0,=GIC_cpu_base
    ldr r0,[r0]
    ldr r0,[r0,#ICCIAR]
    mov pc,lr

// void end_of_interrupt (int ID);
// Notify the GIC that the interrupt has been processed. The state goes from
// active to inactive, or it goes from active and pending to pending.
.global end_of_interrupt
end_of_interrupt:
    ldr r1,=GIC_cpu_base
    ldr r1,[r1]
    str r0,[r1,#ICCEOIR]
    mov pc, lr

// IRQ Handler that calls the ISR function in C
.global irq_handler
irq_handler:
    stmfd sp!,{r0-r7, lr}
    // Call Interrupt Service Routine in C:
    bl ISR
    ldmfd sp!, {r0-r7, lr}
    // Must substract 4 from lr
    subs pc, lr, #4

链接脚本:

ENTRY(_Reset)
SECTIONS
{
 . = 0x0;
 .text : {
 boot.o (INTERRUPT_VECTOR)
 *(.text)
 }
 .data : { *(.data) }
 .bss : { *(.bss COMMON) }
 . = ALIGN(8);
 . = . + 0x1000; /* 4kB of stack memory */
 stack_top = .;
 PROVIDE (end = .)   ;
}

主要C计划:

#include <stdio.h>

extern "C" void config_interrupt(int, int);

volatile unsigned int * const SHADOW = (unsigned int *)0x1000a000;

void sendShadow(unsigned int s)
{
        *SHADOW = s;
}

int main(void)
{
    config_interrupt(47,0);

    unsigned int r = 1337;

    while (1)
    {
        printf("Hello World! %d\n", r);
        sendShadow(1);  
    }
}

void ISR(void)
{
    printf("ISR");
}

0 个答案:

没有答案