Hi All, I am running into a curious issue with QEMU ARM, maybe a Linux/QEMU ARM expert could help before I filed a bug report. Is this a QEMU problem or is there a fundamental problem with my kernel change? QEMU builds before SHA 6ec1588e handle this kernel change just fine...
I'm seeing a very early CPU abort if I add L1 cache invalidation logic in early Linux decompress code in arch/arm/boot/compressed/head.S. Essentially, if I add a copy of v7_invalidate_l1 from arch/arm/mm/cache-v7.S to __armv7_mmu_cache_on in head.S QEMU aborts somewhere inside the new code. Please see the head.S patch below: diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 06e983f..943541f 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -753,6 +753,29 @@ __armv4_mmu_cache_on: __armv7_mmu_cache_on: mov r12, lr +@ r0: Primary Part Number of MIDR[15:4], read from HW +@ r1: Primary Part Number of Cortex A9 +@ r3: Mask for Primary Part Number +@ L1 dcache invalidation is needed for Cortex A9 +@ L1 dcache invalidation is not needed for Cortex A7 as HW does d-cache invalidation during power ON + + mrc 15, 0, r0, c0, c0, 0 @ Read Main ID [MIDR] + @ldr r0, =0xc090 @ Added for testing purpose + ldr r1, =0x0000c090 @ Cortex-A9 MPCore (ARMv7) + ldr r2, =0x0000fff0 @ Mask for Primary Part Number [15:4] + ands r0, r0, r2 @ get the Primary Part Number + eors r0, r1 @ Test whether the core is A9 + beq v7_invalidate @ Allow A9 to perform L1 invalidate + bne l1_self_invalidated @ Only A9 requires L1 cache invalidate +@ Invalidate L1 +v7_invalidate: + stmia sp, {r0-r4, lr} + bl v7_invalidate_l1 @ Allow A9 to perform L1 invalidate + ldmia sp, {r0-r4, lr} + +@ Skip Invalidation, alreay validated in the HW +l1_self_invalidated: + #ifdef CONFIG_MMU mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0 tst r11, #0xf @ VMSA @@ -1253,6 +1276,43 @@ __armv3_mpu_cache_flush: mcr p15, 0, r1, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr + +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift) + mcr p15, 0, r5, c7, c6, 2 + bgt 2b + cmp r2, #0 + bgt 1b + dsb + isb + mov pc, lr +ENDPROC(v7_invalidate_l1) + +/* end of d-cache invalidation +*/ + /* * Various debugging routines for printing hex characters and * memory, which again must be relocatable. The modified kernel boots fine if I revert SHA 6ec1588e that aliases NOR flash at address 0 for vexpress-a9: commit 6ec1588e09770ac7e9c60194faff6101111fc7f0 Author: Peter Maydell <> Date: Wed Jul 2 15:07:50 2014 +0100 hw/arm/vexpress: Alias NOR flash at 0 for vexpress-a9 Make the vexpress-a9 board alias the first NOR flash region at address zero, like vexpress-a15. This makes "-bios" actually usable on this board. diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 3d83e6c..a88732c 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -84,6 +84,7 @@ enum { }; static hwaddr motherboard_legacy_map[] = { + [VE_NORFLASHALIAS] = 0, /* CS7: 0x10000000 .. 0x10020000 */ [VE_SYSREGS] = 0x10000000, [VE_SP810] = 0x10001000, @@ -114,7 +115,6 @@ static hwaddr motherboard_legacy_map[] = { [VE_VIDEORAM] = 0x4c000000, [VE_ETHERNET] = 0x4e000000, [VE_USB] = 0x4f000000, - [VE_NORFLASHALIAS] = -1, /* not present */ };