【问题标题】:ARMv8 exception vectors and handlingARMv8 异常向量和处理
【发布时间】:2017-07-08 22:25:16
【问题描述】:

我正在使用 ARM Cortex A53 处理器,但不知道如何设置中断才能工作。

我已阅读有关此主题的文档,但仍然觉得它令人困惑,并且无法在裸机环境中获得中断。

这是我目前拥有的向量表:

_vectors:
    /* Current EL with SP0 */
    b sync_addr /* Synchronous */
    .balign 128
    b irq_addr  /* IRQ/vIRQ */
    .balign 128
    b fiq_addr  /* FIQ/vFIQ */
    .balign 128
    b serr_addr /* SError/vSError */
    /* Current EL with SPn */
    b sync_addr /* Synchronous */
    .balign 128
    b irq_addr  /* IRQ/vIRQ */
    .balign 128
    b fiq_addr  /* FIQ/vFIQ */
    .balign 128
    b serr_addr /* SError/vSError */
    /* Lower EL with Aarch64 */
    b sync_addr /* Synchronous */
    .balign 128
    b irq_addr  /* IRQ/vIRQ */
    .balign 128
    b fiq_addr  /* FIQ/vFIQ */
    .balign 128
    b serr_addr /* SError/vSError */
    /* Lower EL with Aarch32 */
    b sync_addr /* Synchronous */
    .balign 128
    b irq_addr  /* IRQ/vIRQ */
    .balign 128
    b fiq_addr  /* FIQ/vFIQ */
    .balign 128
    b serr_addr /* SError/vSError */

sync_addr: .word reset_handler
irq_addr:  .word irq_handler
fiq_addr:  .word reset_handler
serr_addr: .word reset_handler

我是通过 ARMv8 程序员指南第 10.4 节获得的。

据我所知,我需要将 VBAR_ELn 寄存器设置为指向表,我就是这样做的:

ldr x0, =_vectors
msr vbar_el1, x0

我还有什么遗漏的吗? 任何帮助或指向参考将不胜感激。

【问题讨论】:

  • 您在桌子上使用了什么对齐方式?查看拆卸并确认处理程序处于正确的偏移量。设置完所有这些后,您是否已启用内核中断?这是在使用轮询完全了解外设以及它何时中断以及如何清除它之后。
  • @old_timer 这就是我到目前为止设置的所有内容......我不知道从哪里继续,这是我第一次不得不编写这种低级的东西。我知道在此之后我确实通过修改 PSTATE 字段中的位来启用中断。我也知道这个处理器有一个 GIC(通用中断控制器),并且已经研究过了,但仍然不知道我应该如何从这里继续前进。
  • 我建议你备份。使用轮询(LED 或最好是 uart,您不需要 printf)来学习/理解相关外围设备的工作原理,如何使其中断状态标志置为有效,然后写入哪些寄存器/等以清除该中断状态。
  • 那么如果你真的有一个 GIC(例如,在树莓派 3 中禁用了 gic)然后轮询 gic 状态寄存器以查看来自外围设备的中断,清除外围设备中断,是吗清除 gic?在那个级别你需要做些什么来清除中断。
  • THEN 开始担心中断向量表,你需要使用 arm-whatever-objdump -D myprogram(.elf)。我喜欢使用 .elf 扩展名,大多数人都不需要检查链接器放置向量的位置,它是否位于处理程序所需的确切地址?然后在 PSTATE 中更改启用

标签: assembly arm arm64


【解决方案1】:

所以我已经有一个例子,你可以学习,接受或放弃......

config.txt(在 sd 卡上):

arm_control=0x200
kernel_old=1
disable_commandline_tags=1

memmap(链接器脚本):

MEMORY
{
    ram : ORIGIN = 0x0000, LENGTH = 0x1000000
}

SECTIONS
{
    .text : { *(.text*) } > ram
    .bss : { *(.bss*) } > ram
}

向量.s

.globl _start
_start:
    b skip
    b hang
    b hang
    b hang
    b hang
    b hang
    b hang
    b hang
.balign 128
    b hang
.balign 128
    b hang
.balign 128
    b hang
.balign 128
    b hang
.balign 128
    b irq_handler

skip:
    // isolate core 0
    mrs x0,mpidr_el1
    mov x1,#0xC1000000
    bic x1,x0,x1
    cbz x1,zero
not_zero:
    wfi
    //msr daifset,#2
    b not_zero
zero:

    mov sp,#0x08000000
    bl notmain
hang: b hang

.globl PUT32
PUT32:
  str w1,[x0]
  ret

.globl GET32
GET32:
    ldr w0,[x0]
    ret

.globl enable_irq
enable_irq:
    //should already be set here
    ldr x1,=0x00000000
    msr vbar_el3,x1
    //route to EL3
    mrs x0,scr_el3
    orr x0,x0,#8
    orr x0,x0,#4
    orr x0,x0,#2
    msr scr_el3,x0
    //clear/enable irq bit in PSTATE
    msr daifclr,#2
    ret

irq_handler:
    //19 up are callee saved
    //so we have to preserve all below?
    stp x0,x1,[sp,#-16]!
    stp x2,x3,[sp,#-16]!
    stp x4,x5,[sp,#-16]!
    stp x6,x7,[sp,#-16]!
    stp x8,x9,[sp,#-16]!
    stp x10,x11,[sp,#-16]!
    stp x12,x13,[sp,#-16]!
    stp x14,x15,[sp,#-16]!
    stp x16,x17,[sp,#-16]!
    stp x18,x19,[sp,#-16]!

    //mrs x0,esr_el3
    bl c_irq_handler

    ldp x18,x19,[sp],#16
    ldp x16,x17,[sp],#16
    ldp x14,x15,[sp],#16
    ldp x12,x13,[sp],#16
    ldp x10,x11,[sp],#16
    ldp x8,x9,[sp],#16
    ldp x6,x7,[sp],#16
    ldp x4,x5,[sp],#16
    ldp x2,x3,[sp],#16
    ldp x0,x1,[sp],#16
    eret

.globl DOWFI
DOWFI:
    wfi
    //msr daifset,#2
    ret

periph.c

#define PBASE 0x3F000000

extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
extern void dummy ( unsigned int );

#define ARM_TIMER_CTL   (PBASE+0x0000B408)
#define ARM_TIMER_CNT   (PBASE+0x0000B420)

#define GPFSEL1         (PBASE+0x00200004)
#define GPSET0          (PBASE+0x0020001C)
#define GPCLR0          (PBASE+0x00200028)
#define GPPUD           (PBASE+0x00200094)
#define GPPUDCLK0       (PBASE+0x00200098)

#define AUX_ENABLES     (PBASE+0x00215004)
#define AUX_MU_IO_REG   (PBASE+0x00215040)
#define AUX_MU_IER_REG  (PBASE+0x00215044)
#define AUX_MU_IIR_REG  (PBASE+0x00215048)
#define AUX_MU_LCR_REG  (PBASE+0x0021504C)
#define AUX_MU_MCR_REG  (PBASE+0x00215050)
#define AUX_MU_LSR_REG  (PBASE+0x00215054)
#define AUX_MU_MSR_REG  (PBASE+0x00215058)
#define AUX_MU_SCRATCH  (PBASE+0x0021505C)
#define AUX_MU_CNTL_REG (PBASE+0x00215060)
#define AUX_MU_STAT_REG (PBASE+0x00215064)
#define AUX_MU_BAUD_REG (PBASE+0x00215068)

//GPIO14  TXD0 and TXD1
//GPIO15  RXD0 and RXD1

unsigned int uart_lcr ( void )
{
    return(GET32(AUX_MU_LSR_REG));
}

unsigned int uart_recv ( void )
{
    while(1)
    {
        if(GET32(AUX_MU_LSR_REG)&0x01) break;
    }
    return(GET32(AUX_MU_IO_REG)&0xFF);
}

unsigned int uart_check ( void )
{
    if(GET32(AUX_MU_LSR_REG)&0x01) return(1);
    return(0);
}

void uart_send ( unsigned int c )
{
    while(1)
    {
        if(GET32(AUX_MU_LSR_REG)&0x20) break;
    }
    PUT32(AUX_MU_IO_REG,c);
}

void uart_flush ( void )
{
    while(1)
    {
        if(GET32(AUX_MU_LSR_REG)&0x40) break;
    }
}

void hexstrings ( unsigned int d )
{
    //unsigned int ra;
    unsigned int rb;
    unsigned int rc;

    rb=32;
    while(1)
    {
        rb-=4;
        rc=(d>>rb)&0xF;
        if(rc>9) rc+=0x37; else rc+=0x30;
        uart_send(rc);
        if(rb==0) break;
    }
    uart_send(0x20);
}

void hexstring ( unsigned int d )
{
    hexstrings(d);
    uart_send(0x0D);
    uart_send(0x0A);
}

void uart_init ( void )
{
    unsigned int ra;

    PUT32(AUX_ENABLES,1);
    PUT32(AUX_MU_IER_REG,0);
    PUT32(AUX_MU_CNTL_REG,0);
    PUT32(AUX_MU_LCR_REG,3);
    PUT32(AUX_MU_MCR_REG,0);
    PUT32(AUX_MU_IER_REG,0);
    PUT32(AUX_MU_IIR_REG,0xC6);
    PUT32(AUX_MU_BAUD_REG,270);
    ra=GET32(GPFSEL1);
    ra&=~(7<<12); //gpio14
    ra|=2<<12;    //alt5
    ra&=~(7<<15); //gpio15
    ra|=2<<15;    //alt5
    PUT32(GPFSEL1,ra);
    //PUT32(GPPUD,0);
    //for(ra=0;ra<150;ra++) dummy(ra);
    //PUT32(GPPUDCLK0,(1<<14)|(1<<15));
    //for(ra=0;ra<150;ra++) dummy(ra);
    //PUT32(GPPUDCLK0,0);
    PUT32(AUX_MU_CNTL_REG,3);
}

notmain.c

extern void PUT32 ( unsigned int, unsigned int );
extern unsigned int GET32 ( unsigned int );
extern void dummy ( unsigned int );
extern void enable_irq ( void );
extern void DOWFI ( void );

extern void uart_init ( void );
extern void uart_send ( unsigned int );
extern void hexstring ( unsigned int );

#define GPFSEL2 0x3F200008
#define GPSET0  0x3F20001C
#define GPCLR0  0x3F200028


#define ARM_TIMER_LOD 0x3F00B400
#define ARM_TIMER_VAL 0x3F00B404
#define ARM_TIMER_CTL 0x3F00B408
#define ARM_TIMER_CLI 0x3F00B40C
#define ARM_TIMER_RIS 0x3F00B410
#define ARM_TIMER_MIS 0x3F00B414
#define ARM_TIMER_RLD 0x3F00B418
#define ARM_TIMER_DIV 0x3F00B41C
#define ARM_TIMER_CNT 0x3F00B420

#define SYSTIMERCLO 0x3F003004
#define GPFSEL1 0x3F200004
#define GPSET0  0x3F20001C
#define GPCLR0  0x3F200028
#define GPFSEL3 0x3F20000C
#define GPFSEL4 0x3F200010
#define GPSET1  0x3F200020
#define GPCLR1  0x3F20002C

#define IRQ_BASIC 0x3F00B200
#define IRQ_PEND1 0x3F00B204
#define IRQ_PEND2 0x3F00B208
#define IRQ_FIQ_CONTROL 0x3F00B210
#define IRQ_ENABLE_BASIC 0x3F00B218
#define IRQ_DISABLE_BASIC 0x3F00B224

volatile unsigned int icount;


void c_irq_handler ( void )
{
    icount++;
    if(icount&1)
    {
        PUT32(GPSET0,1<<21);
        uart_send(0x55);
    }
    else
    {
        PUT32(GPCLR0,1<<21);
        uart_send(0x56);
    }
    PUT32(ARM_TIMER_CLI,0);
}

int notmain ( void )
{
    unsigned int ra;

    PUT32(IRQ_DISABLE_BASIC,1);

    ra=GET32(GPFSEL2);
    ra&=~(7<<3);
    ra|=1<<3;
    PUT32(GPFSEL2,ra);

    uart_init();
if(1)
{
    PUT32(ARM_TIMER_CTL,0x003E0000);
    PUT32(ARM_TIMER_LOD,1000000-1);
    PUT32(ARM_TIMER_RLD,1000000-1);
    PUT32(ARM_TIMER_DIV,0x000000F9);
    PUT32(ARM_TIMER_CLI,0);
    PUT32(ARM_TIMER_CTL,0x003E00A2);

    for(ra=0;ra<2;ra++)
    {
        PUT32(GPSET0,1<<21);
        uart_send(0x55);
        while(1) if(GET32(ARM_TIMER_MIS)) break;
        PUT32(ARM_TIMER_CLI,0);

        PUT32(GPCLR0,1<<21);
        uart_send(0x56);
        while(1) if(GET32(ARM_TIMER_MIS)) break;
        PUT32(ARM_TIMER_CLI,0);
    }
    uart_send(0x0D);
    uart_send(0x0A);
}
if(1)
{
    PUT32(ARM_TIMER_CTL,0x003E0000);
    PUT32(ARM_TIMER_LOD,2000000-1);
    PUT32(ARM_TIMER_RLD,2000000-1);
    PUT32(ARM_TIMER_CLI,0);
    PUT32(IRQ_ENABLE_BASIC,1);
    PUT32(ARM_TIMER_CTL,0x003E00A2);
    for(ra=0;ra<3;ra++)
    {
        PUT32(GPSET0,1<<21);
        uart_send(0x55);
        while(1) if(GET32(IRQ_BASIC)&1) break;
        PUT32(ARM_TIMER_CLI,0);

        PUT32(GPCLR0,1<<21);
        uart_send(0x56);
        while(1) if(GET32(IRQ_BASIC)&1) break;
        PUT32(ARM_TIMER_CLI,0);
    }
    PUT32(IRQ_ENABLE_BASIC,0);
    uart_send(0x0D);
    uart_send(0x0A);
}
    PUT32(ARM_TIMER_CTL,0x003E0000);
    PUT32(ARM_TIMER_LOD,500000-1);
    PUT32(ARM_TIMER_RLD,500000-1);
    PUT32(ARM_TIMER_CLI,0);
    PUT32(IRQ_ENABLE_BASIC,1);
    icount=0;
    enable_irq();
    PUT32(ARM_TIMER_CTL,0x003E00A2);
    PUT32(ARM_TIMER_CLI,0);

    while(1)
    {
        DOWFI();
        uart_send(0x33);
    }
    return(0);
}

构建

aarch64-none-elf-as --warn --fatal-warnings vectors.s -o vectors.o
aarch64-none-elf-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding  -c periph.c -o periph.o
aarch64-none-elf-gcc -Wall -O2 -nostdlib -nostartfiles -ffreestanding  -c notmain.c -o notmain.o
aarch64-none-elf-ld vectors.o periph.o notmain.o -T memmap -o notmain.elf
aarch64-none-elf-objdump -D notmain.elf > notmain.list
aarch64-none-elf-objcopy notmain.elf -O binary kernel8.img

然后检查反汇编以确认一切都在正确的位置。我将零写入 vbar,即使我不应该需要它,因为它应该为零。因此,EL3 的地址/偏移量必须为 0x280,或者它不是 el0/el1 是什么?类似的东西。

0000000000000000 <_start>:
   0:   140000a1    b   284 <skip>
   4:   140000a8    b   2a4 <hang>
   8:   140000a7    b   2a4 <hang>
   c:   140000a6    b   2a4 <hang>
  10:   140000a5    b   2a4 <hang>
  14:   140000a4    b   2a4 <hang>
  18:   140000a3    b   2a4 <hang>
  1c:   140000a2    b   2a4 <hang>
  20:   d503201f    nop
  24:   d503201f    nop
  28:   d503201f    nop
  2c:   d503201f    nop
...
 27c:   d503201f    nop
 280:   14000017    b   2dc <irq_handler>
...

我的猜测是向量之间的差距很大,因此您可以将处理程序放在那里而不是在其他地方分支,但我还是在其他地方分支。

并复制 kernel8.img 和 config.txt(以及 bootcode.bin 和 start.elf 并且没有任何其他具有该名称的 kernel*.img(根据需要重命名或删除)。

第一个 if(1) 轮询外设中的中断。接下来是芯片特定的,因为树莓派 3 有自己的中断逻辑,他们绑定了 GICCDISABLE 来禁用 GIC,所以不要玩这个。最后一个中断是允许的。

正如人们所期望的那样,EL3 中的 pi3 启动器不会弄乱它(如果你甚至可以从核心的边缘,当然可以切换 aarch32 和 aarch64)。

因此,从您离开的地方开始,您需要确保您的矢量位于您设置 vbar 的正确位置/偏移量。我会假设但必须检查vbar是否有对齐要求,也许没有(一些低地址位必须为零)。那么你有所有外围工作要做。 pi 很好(不是其他人),因为一旦您弄清楚如何使外围设备发送中断,您就可以轮询中断状态行以查看外围设备的哪些行发生了变化。使用 Broadcom 文档验证中断行/编号,看看是否有意义,其中一些没有记录,或者您可能必须查看社区驱动的勘误表等。然后很容易允许中断通过,而不是那么复杂作为一个 gic 或其他中断控制器(如果你不想要,不需要在这里做优先级的事情),然后让它进入核心。

我没有弄清楚为什么中断发生时WFI不释放。

【讨论】:

  • 注意:在 ISR 中与 uart 通信是个坏主意,在这种情况下,中断相距很远,在此实现中是安全的,但总的来说是个坏主意。
  • 这只是一个工作示例的参考,将其与您正在做的事情进行比较并制作您自己的程序...
  • 抱歉劫持了一个老问题,但是daifset 指的是msr 指令?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多