我正在ARM-Cortex A53,SoC BCM2837(换句话说是Raspberry PI 3)上进行裸机编程(正在开发内核)。我实际上是在编写负责处理迷你UART的软件(这是一种问候世界,如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代码中没有什么不好的,并且汇编代码中的地址似乎还可以...问题出在哪里?为什么会出现未定义指令异常?如果需要更多信息,我可以提供更多详细信息
答案 0 :(得分:0)
问题出在用于访问外设寄存器的基地址设置错误。一旦将其设置为0x3F000000,就不会再引发异常。
我已将基本地址设置为0x7E000000,误导了BCM数据表中报告的内容:
外围设备的物理地址范围从0x3F000000到0x3FFFFFFF。的 设置外设的总线地址以映射到外设总线地址范围 从0x7E000000开始。因此,此处在总线地址0x7Ennnnnn上发布的外围设备为 在物理地址0x3Fnnnnnn处可用。
但后来报道:
本文档中指定的外围设备地址是总线地址。直接软件 访问外围设备必须将这些地址转换为物理或虚拟地址