我正在 ARM-Cortex A53、SoC BCM2837(即 Raspberry PI 3)上进行裸机编程(我正在开发内核)。我实际上正在编写负责处理迷你 UART 的软件(一种 hello world,如 OsDev wiki https://wiki.osdev.org/ARM_RaspberryPi_Tutorial_C 所报道)。所以我写了一组函数来处理迷你 UART,让我们考虑以下问题,因为任何其他函数仍然存在问题:
void miniUartSendByte(unsigned char byte){
// FIFO can accept at least one byte
while(*AUX_MU_LSR_REG & 0b100000);
// write byte to buffer
*AUX_MU_IO_REG = byte;
return;
}
其中 AUX_MU_* 的类型为 volatile unsigned int*。这是上面代码的反汇编:
1000ac: d10043ff sub sp, sp, #0x10
1000b0: 39003fe0 strb w0, [sp, #15]
1000b4: d503201f nop
1000b8: d28a0a80 mov x0, #0x5054 // #20564
1000bc: f2afc420 movk x0, #0x7e21, lsl #16
1000c0: b9400000 ldr w0, [x0]
1000c4: 121b0000 and w0, w0, #0x20
1000c8: 7100001f cmp w0, #0x0
1000cc: 54ffff61 b.ne 1000b8 <miniUartSendByte+0xc> // b.any
1000d0: d28a0800 mov x0, #0x5040 // #20544
1000d4: f2afc420 movk x0, #0x7e21, lsl #16
1000d8: 39403fe1 ldrb w1, [sp, #15]
1000dc: b9000001 str w1, [x0]
1000e0: d503201f nop
1000e4: 910043ff add sp, sp, #0x10
1000e8: d65f03c0 ret
这是 QEMU 报告的执行:
----------------
IN: kernel_main
0x00100050: a9bf7bfd stp x29, x30, [sp, #-0x10]!
0x00100054: 910003fd mov x29, sp
0x00100058: 52800c60 movz w0, #0x63
0x0010005c: 94000012 bl #0x1000a4 // jump to miniUartSendByte
----------------
IN: miniUartSendByte
0x001000a4: d10043ff sub sp, sp, #0x10
0x001000a8: 39003fe0 strb w0, [sp, #0xf]
0x001000ac: d503201f nop
0x001000b0: d28a0a80 movz x0, #0x5054
0x001000b4: f2afc420 movk x0, #0x7e21, lsl #16
0x001000b8: b9400000 ldr w0, [x0]
0x001000bc: 121b0000 and w0, w0, #0x20
0x001000c0: 7100001f cmp w0, #0
0x001000c4: 54ffff61 b.ne #0x1000b0
----------------
IN:
0x00000200: 00000000 .byte 0x00, 0x00, 0x00, 0x00 // ??
可以看到,机器在执行跳转的时候,收到异常,跳转到地址0x200,这里是放置中断处理程序的地方(注意,没有配置中断处理程序,我还没实现)并卡在地址 0x200 执行无限循环(不存在中断处理程序时的默认行为)。现在,我可以从 QEMU 捕获异常类型:
Taking exception 1 [Undefined Instruction]
...from EL3 to EL3
...with ESR 0x0/0x2000000
...with ELR 0x200
...to EL3 PC 0x200 PSTATE 0x3cd
我正在使用以下命令进行编译:
aarch64-elf-gcc -Wall -O0 -ffreestanding -nostdinc -nostdlib -nostartfiles -mcpu=cortex-a53 -g -c ... -o ...
我还尝试查看这是否是“编译器”问题,尝试执行以下完全无用的代码:
void a(){
for(int j=0; j<10; j++);
return;
}
void b(char* string){
for(int i = 0; i<10; i++){
a();
}
return;
}
void kernel_main(){
a();
b("test");
while(1);
return;
}
但是执行没有任何问题...... 现在我不知道出了什么问题。我的意思是,生成该汇编程序的 C 代码没有任何问题,而且汇编代码中的地址似乎没问题……知道问题出在哪里吗?为什么会出现未定义指令异常??如果需要更多信息,我可以提供更多详细信息
最佳答案
问题出在访问外设寄存器的基址设置错误。一旦将其设置为 0x3F000000,就不会再引发异常。
我将基地址设置为 0x7E000000,误导了 BCM 数据表中的报告:
Physical addresses range from 0x3F000000 to 0x3FFFFFFF for peripherals. The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000. Thus a peripheral advertised here at bus address 0x7Ennnnnn is available at physical address 0x3Fnnnnnn.
但后来报道:
The peripheral addresses specified in this document are bus addresses. Software directly accessing peripherals must translate these addresses into physical or virtual addresses
关于c - ARM代码中的未定义指令异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56345771/