Assembly ARMv8异常向量和处理
我正在使用ARM Cortex A53处理器,不知道如何设置中断来工作 我已经阅读了关于这个主题的文档,但仍然发现它令人困惑,并且无法在裸机环境中使用中断 以下是我目前拥有的向量表:Assembly ARMv8异常向量和处理,assembly,arm,arm64,Assembly,Arm,Arm64,我正在使用ARM Cortex A53处理器,不知道如何设置中断来工作 我已经阅读了关于这个主题的文档,但仍然发现它令人困惑,并且无法在裸机环境中使用中断 以下是我目前拥有的向量表: _vectors: /* Current EL with SP0 */ b sync_addr /* Synchronous */ .balign 128 b irq_addr /* IRQ/vIRQ */ .balign 128 b fiq_addr /* FI
_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
我还缺什么吗?
非常感谢您提供的任何帮助或参考资料。所以我已经有了一个例子,您可以学习、接受或放弃它 config.txt(位于sd卡上): memmap(链接器脚本): 向量
.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
周边
#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);
}
然后检查拆卸以确认所有部件都在正确的位置。我将零写入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>
...
0000000000000000:
0:140000a1 b 284
4:140000a8 b 2a4
8:140000A7B2A4
c:140000a6 b 2a4
10:140000a5 b 2a4
14:140000a4 b 2a4
18:140000a3 b 2a4
1c:140000a2 b 2a4
20:d503201f无
24:d503201f无
28:d503201f无
2c:d503201f nop
...
27c:d503201f编号
280:14000017 b 2dc
...
我猜向量之间的差距很大,所以你可以把处理程序放在那里,而不是转移到其他地方,但我还是转移到了其他地方
并复制kernel8.img和config.txt(以及bootcode.bin和start.elf),并且没有任何其他具有该名称的kernel*.img(根据需要重命名或删除)
第一个if(1)轮询外设中的中断。下一个是特定于芯片的,因为raspberry pi 3有自己的中断逻辑,他们绑定了GICCDISABLE以禁用GIC,所以不要玩它。最后一个中断是允许的
在EL3中的pi3靴子,正如人们所期望的那样,它们不会弄乱它(如果你甚至可以从核心的边缘,当然可以切换aarch32对aarch64)
因此,从您离开的地方开始,您需要确保向量位于正确的位置/偏离设置vbar的位置。我假设,但必须检查vbar是否有对齐要求,可能没有(一些较低的地址位必须为零)。然后您就有所有外围工作要做。pi很好(并非其他人不是)在这种情况下,您可以轮询中断状态行,以查看如何使您的外围设备发送中断后,您的外围设备的哪些行发生了变化。请使用broadcom文档验证中断行/中断号,并查看是否有意义,其中一些未记录,或者您可能必须查看社区驱动的勘误表等。然后,我将它很容易让中断通过,不像gic或其他中断控制器那样复杂(如果你不想,这里不需要做优先级的事情),然后允许它进入内核
我没有弄清楚的是,当中断发生时,WFI为什么不释放。您在工作台上使用了什么对齐方式?查看反汇编并确认处理程序处于正确的偏移量。在设置所有这些之后,您已经启用了对核心的中断?这是在使用轮询来完全了解外围设备和处理器之后当它中断时以及如何清除它。@old_timer这是我到目前为止设置的所有设置…我不知道在哪里继续,这是我第一次不得不编写如此低级的程序。我知道在此之后,我确实通过修改PSTATE字段中的位来启用中断。我还知道这个处理器有一个GIC(通用中断控制器),并且已经研究过了,但是仍然没有关于我应该如何从这里继续前进的线索。我建议您备份。使用轮询(LED或更喜欢uart,您不需要printf)要了解/理解相关外设的工作原理,如何使其中断状态标志断言,然后写入什么寄存器/等以清除中断状态。如果您确实有GIC(例如,在raspberry pi 3中禁用GIC)然后轮询gic状态寄存器以查看来自外设的中断,清除外设中断,它是否清除gic?在该级别是否需要执行任何操作以清除中断。然后开始担心中断向量表,您需要使用arm任何objdump-D myprogram(.elf)。我喜欢使用.elf扩展。大多数人都不需要这样做。您需要检查链接器将向量放置在何处,它是否位于处理程序所需的确切地址?然后更改PState中的enable注意:在ISR中与uart对话是个坏主意,在这种情况下,中断距离非常远,在这种实现中是安全的,b但总的来说这是一个坏主意。这只是一个工作示例的参考,将其与您正在做的事情进行比较,并制作您自己的程序……很抱歉劫持一个老问题,但是
daifset
对于msr
指令指的是什么?
#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);
}
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
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>
...