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
@ -8,20 +8,64 @@ ARM_SRC=$(SRC_PATH)/tests/tcg/arm/system
|
||||
# Set search path for all sources
|
||||
VPATH += $(ARM_SRC)
|
||||
|
||||
ARM_TESTS=test-armv6m-undef
|
||||
|
||||
TESTS += $(ARM_TESTS)
|
||||
|
||||
LDFLAGS+=-nostdlib -N -static
|
||||
|
||||
%: %.S %.ld
|
||||
$(CC) $(CFLAGS) $(ASFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -T $(ARM_SRC)/$@.ld
|
||||
|
||||
# Specific Test Rules
|
||||
|
||||
test-armv6m-undef: EXTRA_CFLAGS+=-mcpu=cortex-m0 -mfloat-abi=soft -Wl,--build-id=none -x assembler-with-cpp
|
||||
test-armv6m-undef: test-armv6m-undef.S
|
||||
$(CC) -mcpu=cortex-m0 -mfloat-abi=soft \
|
||||
-Wl,--build-id=none -x assembler-with-cpp \
|
||||
$< -o $@ -nostdlib -N -static \
|
||||
-T $(ARM_SRC)/$@.ld
|
||||
|
||||
run-test-armv6m-undef: QEMU_OPTS+=-semihosting -M microbit -kernel
|
||||
|
||||
# We don't currently support the multiarch system tests
|
||||
undefine MULTIARCH_TESTS
|
||||
ARM_TESTS+=test-armv6m-undef
|
||||
|
||||
# These objects provide the basic boot code and helper functions for all tests
|
||||
CRT_OBJS=boot.o
|
||||
|
||||
ARM_TEST_SRCS=$(wildcard $(ARM_SRC)/*.c)
|
||||
ARM_TESTS+=$(patsubst $(ARM_SRC)/%.c, %, $(ARM_TEST_SRCS))
|
||||
|
||||
CRT_PATH=$(ARM_SRC)
|
||||
LINK_SCRIPT=$(ARM_SRC)/kernel.ld
|
||||
LDFLAGS=-Wl,-T$(LINK_SCRIPT)
|
||||
CFLAGS+=-nostdlib -ggdb -O0 $(MINILIB_INC)
|
||||
LDFLAGS+=-static -nostdlib -N $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
|
||||
|
||||
# building head blobs
|
||||
.PRECIOUS: $(CRT_OBJS)
|
||||
|
||||
%.o: $(ARM_SRC)/%.S
|
||||
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
|
||||
|
||||
# Build and link the tests
|
||||
%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
|
||||
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
|
||||
|
||||
memory: CFLAGS+=-DCHECK_UNALIGNED=0
|
||||
|
||||
# Running
|
||||
QEMU_BASE_MACHINE=-M virt -cpu max -display none
|
||||
QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel
|
||||
|
||||
# Simple Record/Replay Test
|
||||
.PHONY: memory-record
|
||||
run-memory-record: memory-record memory
|
||||
$(call run-test, $<, \
|
||||
$(QEMU) -monitor none -display none \
|
||||
-chardev file$(COMMA)path=$<.out$(COMMA)id=output \
|
||||
-icount shift=5$(COMMA)rr=record$(COMMA)rrfile=record.bin \
|
||||
$(QEMU_OPTS) memory)
|
||||
|
||||
.PHONY: memory-replay
|
||||
run-memory-replay: memory-replay run-memory-record
|
||||
$(call run-test, $<, \
|
||||
$(QEMU) -monitor none -display none \
|
||||
-chardev file$(COMMA)path=$<.out$(COMMA)id=output \
|
||||
-icount shift=5$(COMMA)rr=replay$(COMMA)rrfile=record.bin \
|
||||
$(QEMU_OPTS) memory)
|
||||
|
||||
EXTRA_RUNS+=run-memory-replay
|
||||
|
||||
TESTS += $(ARM_TESTS) $(MULTIARCH_TESTS)
|
||||
EXTRA_RUNS+=$(MULTIARCH_RUNS)
|
||||
|
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:
|
24
tests/tcg/arm/system/kernel.ld
Normal file
24
tests/tcg/arm/system/kernel.ld
Normal file
@ -0,0 +1,24 @@
|
||||
ENTRY(__start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* virt machine, RAM starts at 1gb */
|
||||
. = (1 << 30);
|
||||
.text : {
|
||||
*(.text)
|
||||
}
|
||||
.rodata : {
|
||||
*(.rodata)
|
||||
}
|
||||
/* align r/w section to next 2mb */
|
||||
. = ALIGN(1 << 21);
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
.bss : {
|
||||
*(.bss)
|
||||
}
|
||||
/DISCARD/ : {
|
||||
*(.ARM.attributes)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user