Hi, I’m writing a simple debugger in assembly code for the Raspberry Pi 3B (in aarch64).
I’m using QEMU 7.0.0. Everything is running in EL1. (I have MDE and KDE set in MDSCR_EL1). I’m coming across Unexpected Behaviour when playing with single-stepping: It appears that single-stepping is enabled (ie. an exception is generated after every instruction) when the SS bit (bit-0) is set in MDSCR_EL1 and debug events are enabled in the CPSR (“D” bit clear) *** irrespective of whether the SS bit (bit-21) is set in CPSR or not ***. I thought the SS bit (bit-21) needs to be set in CPSR for single-stepping to occur (and that it gets cleared whenever an exception is taken and needs to be reset if one wants to single-step again). Have I misunderstood / misconfigured something, or is this a bug? Attached is a minimal(ish) example: Regards, chris /* ****************************************************************************************** **** built with **** aarch64-elf-as -march=armv8-a+crc+crypto -mcpu=cortex-a53 --gstabs minimal.s -o minimal.o aarch64-elf-ld minimal.o -T memmap -o minimal.elf aarch64-elf-objcopy -O binary minimal.elf minimal.img aarch64-elf-objdump -d -j .text minimal.elf > minimal.list **** memmap is **** MEMORY { ram : ORIGIN = 0x80000, LENGTH = 0x80000000 } SECTIONS { .init : { *(.init*) } > ram .text : { *(.text*) } > ram .data : { *(.data*) } > ram .bss : { *(.bss*) } > ram } **** qemu cmd **** qemu-7.0.0/build/qemu-system-aarch64 -M raspi3b -kernel minimal.img -serial null -serial stdio -s -S **** gdb cmd **** /opt/local/gnuaarch64/bin/aarch64-none-elf-gdb -x gdb.cmds minimal.elf **** gdb.cmds is **** target remote :1234 set $pc = 0x80000 ****************************************************************************************** */ .section .text .global _start _start: mrs x0, mpidr_el1 // x0 = 00000000.8000.0000 and x0, x0, 0b11 cbz x0, 2f // branch fwd if core == 0 ... 1: wfe // ... else wait for exception (ie sleep) b 1b 2: // mrs x0, scr_el3 // Can't access this from EL2. But gdb says it's 0x0501 // 0000.0101|0000.0001 10:RW=1 8:HCE=1 0:NS=1 // mrs x0, hcr_el2 // x0 -> 1<<31 (34:E2H=0 31:RW=1 27:TGE=0 2:C=0 1:M=0) // mrs x0, sctlr_el1 // x0 -> 00c5.0838 = 0000.0000|1100.0101|0000.1000|0011.1000 mov x0, 0x0800 // -SA -SA0, -CP15BEN -nTWE -nTWI +20:RES1 +28:RES1 +29:RES1 movk x0, 0x30d0, lsl 16 // x0 -> 30d0.0800 = 0011.0000|1101.0000|0000.1000|0000.0000 msr sctlr_el1, x0 adr x0, vectors msr vbar_el1, x0 adr x0, _start // 0x0008.0000 = 512k msr sp_el1, x0 // set EL1's SP mov x0, 0x3c5 // NOTE: bit 21:SS is NOT set msr spsr_el2, x0 // DAIF exceptions masked. A64 state. EL1. SP = SP_ELx adr x0, init msr elr_el2, x0 eret // We're in EL2. Pretend we're "returning" to EL1 init: init: msr OSLAR_EL1, xzr // unlock OS lock mov x0, 0b101<<13 // 15:MDE (enable debugging) and 13:KDE (and kernel debug events) orr x0, x0, 0b1<<0 // enable SS debug exceptions msr MDSCR_EL1, x0 mov w0, 0 // these all execute ok mov w0, 1 b 1f mov w0, -1 1: msr daifclr, 0b1111 // enable all interrupts and debugging exceptions mov w0, 3 // this causes an exception ESR_EL1 = 0xce000022 (see ARMv8ARM D1-1801) mov w0, 4 // 0xce = 0b1100.1110|- >> 26 = 0b0011.0011 = 0x33 = exception class // ie. SS from same EL. ** even though CPSR was 0x00000005 ** svc 124 mov w0, 5 b 2f mov w0, -2 2: mov w0, 6 loop: b loop // ****************************************************************************************************** exc_svc: and w0, w0, 0xffff cmp w0, 123 beq svc_123 cmp w0, 124 beq svc_124 b exception_return // undefined SVCs ignored svc_123: mrs x0, SPSR_EL1 orr x0, x0, 0b1<<21 // (re)enable SS in CPSR msr SPSR_EL1, x0 b exception_return svc_124: mrs x0, SPSR_EL1 bic x0, x0, 0b1<<21 // disable SS in CPSR (not really necessary since SS gets msr SPSR_EL1, x0 // cleared when an exception (eg. SVC) gets taken anyway) b exception_return exc_dbg: mrs x0, elr_el1 mrs x0, SPSR_EL1 bic x0, x0, 0b1<<21 // (re)enable SS in CPSR msr SPSR_EL1, x0 b exception_return exception_return: ldp x2, x3, [sp], 16 ldp x0, x1, [sp], 16 eret .align 11 vectors: // ************************ from current EL using SP_EL0 *************************** v0: // Synchronous b v0 .align 7 v1: // IRQ b v1 .align 7 v2: // FIQ b v2 .align 7 v3: // SError b v3 // ************************ from current EL using SP_EL1+ ************************** .align 7 v10: // Synchronous (SVC, MMU, DEBUG) stp x0, x1, [sp, -16]! stp x2, x3, [sp, -16]! mrs x0, esr_el1 // exception syndrome (ARMv8ARM p. D1-1801) mov w1, w0, lsr 26 // w1 -> exception class cmp w1, 0x15 // SVC beq exc_svc b exc_dbg .align 7 v11: // IRQ b v11 .align 7 v12: // FIQ b v12 .align 7 v13: // SError b v13 // ************************ from lower EL using A64 ******************************** .align 7 v20: // Synchronous b v20 .align 7 v21: // IRQ b v21 .align 7 v22: // FIQ b v22 .align 7 v23: // SError b v23 // ********************************************************************************* data: