我正在研究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
还有什么我想念的吗? 任何帮助或指向参考将不胜感激。
答案 0 :(得分:0)
所以我已经有了一个例子,你可以学习,接受或离开它......
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
}
vectors.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,没有任何其他内核* .img具有该名称(根据需要重命名或删除)。
第一个if(1)轮询外设中的中断。接下来是芯片特定的,因为树莓派3有自己的中断逻辑,他们绑定了GICCDISABLE来禁用GIC,所以不要去玩。最后一次中断是允许的。
pi3在EL3中启动,因为人们会认为它们不会弄乱它(如果你甚至可以从核心的边缘,可以肯定地转换aarch32与aarch64)。
因此,从您离开的地方开始,您需要确保您的矢量位于正确位置/偏离您设置vbar的位置。我会假设但是必须检查vbar是否存在对齐要求,可能没有(某些低位地址位必须为零)。然后你有所有的外围工作要做。 pi非常好(不是其他人不是),因为一旦你弄清楚如何让外设发送中断,你可以轮询中断状态行以查看外围设备的哪些线路发生了变化。使用broadcom文档验证中断行/编号并查看是否有意义,其中一些没有记录,或者您必须查看社区驱动的勘误表等。然后很容易让中断通过,而不是复杂作为一个gic或其他中断控制器(如果你不想要的话,不需要在这里做优先事项)然后允许它进入核心。
我还没想到的是为什么WFI在中断发生时不释放。