mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 17:23:56 -06:00
tests/tcg: enable arm softmmu tests
To make it easier to test 32 bit Arm softmmu issues implement a basic boot.S so we can build the multiarch tests. Currently CHECK_UNALIGNED is disabled as I haven't got the right magic set for it to work. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20231120150833.2552739-12-alex.bennee@linaro.org>
This commit is contained in:
parent
e8368b1c95
commit
56611e17d2
3 changed files with 399 additions and 12 deletions
319
tests/tcg/arm/system/boot.S
Normal file
319
tests/tcg/arm/system/boot.S
Normal file
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
* Minimal ArmV7 system boot code.
|
||||
*
|
||||
* Using semihosting for serial output and exit functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Semihosting interface on ARM AArch32
|
||||
* R0 - semihosting call number
|
||||
* R1 - semihosting parameter
|
||||
*/
|
||||
#define semihosting_call svc 0x123456
|
||||
#define SYS_WRITEC 0x03 /* character to debug channel */
|
||||
#define SYS_WRITE0 0x04 /* string to debug channel */
|
||||
#define SYS_EXIT 0x18
|
||||
|
||||
#define ADP_Stopped_ApplicationExit 0x20026
|
||||
#define ADP_Stopped_InternalError 0x20024
|
||||
|
||||
/*
|
||||
* Helper macro for annotating functions with elf type and size.
|
||||
*/
|
||||
.macro endf name
|
||||
.global \name
|
||||
.type \name, %function
|
||||
.size \name, . - \name
|
||||
.endm
|
||||
|
||||
.section .interrupt_vector, "ax"
|
||||
.align 5
|
||||
|
||||
vector_table:
|
||||
b reset /* reset vector */
|
||||
b undef_instr /* undefined instruction vector */
|
||||
b software_intr /* software interrupt vector */
|
||||
b prefetch_abort /* prefetch abort vector */
|
||||
b data_abort /* data abort vector */
|
||||
nop /* reserved */
|
||||
b IRQ_handler /* IRQ vector */
|
||||
b FIQ_handler /* FIQ vector */
|
||||
|
||||
endf vector_table
|
||||
|
||||
.text
|
||||
__start:
|
||||
ldr r0, =vector_table
|
||||
mcr p15, 0, r0, c12, c0, 0 /* Set up VBAR */
|
||||
|
||||
ldr sp, =stack_end /* Set up the stack */
|
||||
bl mmu_setup /* Set up the MMU */
|
||||
bl main /* Jump to main */
|
||||
|
||||
endf __start
|
||||
|
||||
_exit:
|
||||
cmp r0, #0
|
||||
ite EQ // if-then-else. "EQ" is for if equal, else otherwise
|
||||
ldreq r1, =ADP_Stopped_ApplicationExit // if r0 == 0
|
||||
ldrne r1, =ADP_Stopped_InternalError // else
|
||||
mov r0, #SYS_EXIT
|
||||
semihosting_call
|
||||
|
||||
endf _exit
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
mmu_setup:
|
||||
/*
|
||||
* The MMU setup for this is very simple using two stage one
|
||||
* translations. The first 1Mb section points to the text
|
||||
* section and the second points to the data and rss.
|
||||
* Currently the fattest test only needs ~50k for that so we
|
||||
* have plenty of space.
|
||||
*
|
||||
* The short descriptor Section format is as follows:
|
||||
*
|
||||
* PA[31:20] - Section Base Address
|
||||
* NS[19] - Non-secure bit
|
||||
* 0[18] - Section (1 for Super Section)
|
||||
* nG[17] - Not global bit
|
||||
* S[16] - Shareable
|
||||
* TEX[14:12] - Memory Region Attributes
|
||||
* AP[15, 11:10] - Access Permission Bits
|
||||
* IMPDEF[9]
|
||||
* Domain[8:5]
|
||||
* XN[4] - Execute never bit
|
||||
* C[3] - Memory Region Attributes
|
||||
* B[2] - Memory Region Attributes
|
||||
* 1[1]
|
||||
* PXN[0] - Privileged Execute Never
|
||||
*
|
||||
* r0 - point at the table
|
||||
* r1 - address
|
||||
* r2 - entry
|
||||
* r3 - common section bits
|
||||
* r4 - scratch
|
||||
*/
|
||||
|
||||
/*
|
||||
* Memory Region Bits
|
||||
*
|
||||
* TEX[14:12] = 000
|
||||
* C[3] = 1
|
||||
* B[2] = 1
|
||||
*
|
||||
* Outer and Inner WB, no write allocate
|
||||
*/
|
||||
mov r3, #0
|
||||
ldr r4, =(3 << 2)
|
||||
orr r3, r4, r4
|
||||
|
||||
/* Section bit */
|
||||
orr r3, r3, #2
|
||||
|
||||
/* Page table setup (identity mapping). */
|
||||
ldr r0, =ttb
|
||||
|
||||
/* First block: .text/RO/execute enabled */
|
||||
ldr r1, =.text
|
||||
ldr r2, =0xFFF00000 /* 1MB block alignment */
|
||||
and r2, r1, r2
|
||||
orr r2, r2, r3 /* common bits */
|
||||
orr r2, r2, #(1 << 15) /* AP[2] = 1 */
|
||||
orr r2, r2, #(1 << 10) /* AP[0] = 1 => RO @ PL1 */
|
||||
|
||||
lsr r4, r2, #(20 - 2)
|
||||
str r2, [r0, r4, lsl #0] /* write entry */
|
||||
|
||||
/* Second block: .data/RW/no execute */
|
||||
ldr r1, =.data
|
||||
ldr r2, =0xFFF00000 /* 1MB block alignment */
|
||||
and r2, r1, r2
|
||||
orr r2, r2, r3 /* common bits */
|
||||
orr r2, r2, #(1 << 10) /* AP[0] = 1 => RW @ PL1 */
|
||||
orr r2, r2, #(1 << 4) /* XN[4] => no execute */
|
||||
|
||||
lsr r4, r2, #(20 - 2)
|
||||
str r2, [r0, r4, lsl #0] /* write entry */
|
||||
|
||||
/*
|
||||
* DACR - Domain Control
|
||||
*
|
||||
* Enable client mode for domain 0 (we don't use any others)
|
||||
*/
|
||||
ldr r0, =0x1
|
||||
mcr p15, 0, r0, c3, c0, 0
|
||||
|
||||
/*
|
||||
* TTCBR - Translation Table Base Control Register
|
||||
*
|
||||
* EAE[31] = 0, 32-bit translation, short descriptor format
|
||||
* N[2:0] = 5 ( TTBRO uses 31:14-5 => 9 bit lookup stage )
|
||||
*/
|
||||
ldr r0, =0x5
|
||||
mcr p15, 0, r0, c1, c0, 2
|
||||
|
||||
/*
|
||||
* TTBR0 -Translation Table Base Register 0
|
||||
*
|
||||
* [31:9] = Base address of table
|
||||
*
|
||||
* QEMU doesn't really care about the cache sharing
|
||||
* attributes so we don't need to either.
|
||||
*/
|
||||
ldr r0, =ttb
|
||||
mcr p15, 0, r0, c2, c0, 0
|
||||
|
||||
/*
|
||||
* SCTLR- System Control Register
|
||||
*
|
||||
* TE[30] = 0, exceptions to A32 state
|
||||
* AFE[29] = 0, AP[0] is the access permissions bit
|
||||
* EE[25] = 0, Little-endian
|
||||
* WXN[19] = 0 = no effect, Write does not imply XN (execute never)
|
||||
* I[12] = Instruction cachability control
|
||||
* C[2] = Data cachability control
|
||||
* M[0] = 1, enable stage 1 address translation for EL0/1
|
||||
*
|
||||
* At this point virtual memory is enabled.
|
||||
*/
|
||||
ldr r0, =0x1005
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
isb
|
||||
|
||||
mov pc, lr /* done, return to caller */
|
||||
|
||||
endf mmu_setup
|
||||
|
||||
/* Output a single character to serial port */
|
||||
__sys_outc:
|
||||
STMFD sp!, {r0-r1} // push r0, r1 onto stack
|
||||
mov r1, sp
|
||||
mov r0, #SYS_WRITEC
|
||||
semihosting_call
|
||||
LDMFD sp!, {r0-r1} // pop r0, r1 from stack
|
||||
bx lr
|
||||
|
||||
endf __sys_outc
|
||||
|
||||
reset:
|
||||
ldr r1, =reset_error
|
||||
b exception_handler
|
||||
|
||||
endf reset
|
||||
|
||||
undef_instr:
|
||||
ldr r1, =undef_intr_error
|
||||
b exception_handler
|
||||
|
||||
endf undef_instr
|
||||
|
||||
software_intr:
|
||||
ldr r1, =software_intr_error
|
||||
b exception_handler
|
||||
|
||||
endf software_intr
|
||||
|
||||
prefetch_abort:
|
||||
ldr r1, =prefetch_abort_error
|
||||
b exception_handler
|
||||
|
||||
endf prefetch_abort
|
||||
|
||||
data_abort:
|
||||
ldr r1, =data_abort_error
|
||||
b exception_handler
|
||||
|
||||
endf data_abort
|
||||
|
||||
IRQ_handler:
|
||||
ldr r1, =irq_error
|
||||
b exception_handler
|
||||
|
||||
endf IRQ_handler
|
||||
|
||||
FIQ_handler:
|
||||
ldr r1, =fiq_error
|
||||
b exception_handler
|
||||
|
||||
endf FIQ_handler
|
||||
|
||||
/*
|
||||
* Initiate a exit semihosting call whenever there is any exception
|
||||
* r1 already holds the string.
|
||||
*/
|
||||
exception_handler:
|
||||
mov r0, #SYS_WRITE0
|
||||
semihosting_call
|
||||
mov r0, #SYS_EXIT
|
||||
mov r1, #1
|
||||
semihosting_call
|
||||
|
||||
endf exception_handler
|
||||
|
||||
/*
|
||||
* We implement a stub raise() function which errors out as tests
|
||||
* shouldn't trigger maths errors.
|
||||
*/
|
||||
.global raise
|
||||
raise:
|
||||
mov r0, #SYS_WRITE0
|
||||
ldr r1, =maths_error
|
||||
semihosting_call
|
||||
mov r0, #SYS_EXIT
|
||||
ldr r1, =ADP_Stopped_InternalError
|
||||
semihosting_call
|
||||
|
||||
endf raise
|
||||
|
||||
.data
|
||||
|
||||
.data
|
||||
|
||||
reset_error:
|
||||
.ascii "Reset exception occurred.\n\0"
|
||||
|
||||
undef_intr_error:
|
||||
.ascii "Undefined Instruction Exception Occurred.\n\0"
|
||||
|
||||
software_intr_error:
|
||||
.ascii "Software Interrupt Occurred.\n\0"
|
||||
|
||||
prefetch_abort_error:
|
||||
.ascii "Prefetch Abort Occurred.\n\0"
|
||||
|
||||
data_abort_error:
|
||||
.ascii "Data Abort Occurred.\n\0"
|
||||
|
||||
irq_error:
|
||||
.ascii "IRQ exception occurred.\n\0"
|
||||
|
||||
fiq_error:
|
||||
.ascii "FIQ exception occurred.\n\0"
|
||||
|
||||
maths_error:
|
||||
.ascii "Software maths exception.\n\0"
|
||||
|
||||
|
||||
/*
|
||||
* 1st Stage Translation table
|
||||
* 4096 entries, indexed by [31:20]
|
||||
* each entry covers 1Mb of address space
|
||||
* aligned on 16kb
|
||||
*/
|
||||
.align 15
|
||||
ttb:
|
||||
.space (4096 * 4), 0
|
||||
|
||||
.align 12
|
||||
|
||||
/* Space for stack */
|
||||
.align 5
|
||||
.section .bss
|
||||
stack:
|
||||
.space 65536, 0
|
||||
stack_end:
|
Loading…
Add table
Add a link
Reference in a new issue