Я занимаюсь программированием с нуля (разрабатываю ядро) на 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, производящем этот ассемблер, и адреса в ассемблерном коде кажутся нормальными ... любая идея, где возникает проблема ?? Почему это неопределенное исключение в инструкции ?? Если потребуется дополнительная информация, я могу предоставить более подробную информацию