【问题标题】:Undefined Instruction exception in ARM codeARM代码中的未定义指令异常
【发布时间】:2019-10-14 04:37:20
【问题描述】:

我正在 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 代码没有什么不好的,并且汇编代码中的地址似乎还可以……知道问题出在哪里吗?为什么那个未定义的指令异常?如果需要更多信息,我可以提供更多详细信息

【问题讨论】:

  • 你用unsigned int *AUX_MU_IO_REG写一个字节有什么原因吗?这将写入至少 16 位。结果还会写入什么内容?
  • well unisgned int* 指的是AUX_MU_IO_REG映射到的地址寄存器,换句话说要写入AUX_MU_IO_REG我需要写入该内存位置,此外根据BCM2837数据表,即使寄存器是32位宽,只有前8位可以访问,所以我一次只能写一个字节,其余的都被忽略了。此外,我见过的任何代码 sn-p 都使用 volatile unsigned int* 来访问寄存器(例如,看一下问题中的 OsDev 链接,函数 mmio_write() 正是我所做的(除了他们使用 uint32_t 而不是 unsigned int )
  • 大概那么处理器是little-endian。
  • 好的,根据 ARM 文档 (infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500e/…) 指令总是小端的。你能解释一下这对执行有何影响吗?我的意思是为什么 miniUartSendByte() 会导致跳转异常,而像 a() 或 b() 这样的函数却不会?此外,如果问题出在寄存器中存储的数据中,我不应该遇到关于 UART 行为的问题(我不知道,我想发送 'c' 但发送的是完全不同的东西)而不是代码执行问题??抱歉,我有点困惑……
  • 我尝试在 gcc 中使用 -mlittle-endian 标志进行编译,但结果没有改变。实际上 gcc 已经以小端格式编译(我认为它能够通过查看 -mcpu 参数来检测目标的字节序),实际上如果我使用 -mbig-endian 编译,则返回以下内容“为大端系统编译目标是小端”。我不认为这是问题......

标签: c exception arm kernel bare-metal


【解决方案1】:

问题在于用于访问外设寄存器的基地址设置错误。一旦将其设置为 0x3F000000,就不会再引发异常。

我已将基地址设置为 0x7E000000,误导了 BCM 数据表中报告的内容:

外设的物理地址范围从 0x3F000000 到 0x3FFFFFFF。这 外设的总线地址设置为映射到外设总线地址范围 从 0x7E000000 开始。因此,此处在总线地址 0x7Ennnnnn 处通告的外设是 在物理地址 0x3Fnnnnnn 可用。

但后来被举报:

本文档中指定的外设地址是总线地址。软件直接 访问外设必须将这些地址转换为物理或虚拟地址

【讨论】:

    猜你喜欢
    • 2013-03-04
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    • 2013-04-11
    • 2012-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多