mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
target-arm queue:
* Fix the CBAR register implementation for Cortex-A53, Cortex-A57, Cortex-A72 * Fix direct booting of Linux kernels on emulated CPUs which have an AArch32 EL3 (incorrect NSACR settings meant they could not access the FPU) * semihosting cleanup: do more work at translate time and less work at runtime -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl2OHYsZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oHlD/4iD57WzVkf2EagPg61EbqV KJU0bloj6lpfhI410zv6RLfSxRhuJKj1voBPl0wh/uWz4kIHBjcYZgRQGZz5+Fem XE4j7bLfgXlbYkjl6CFo3oqZJM+iVmMofKVbpj7nEnO6cB9nW2O4Uk88vPTqCRUp uip/ZveoQ3WvzyM8ERWiIiGZrvCRPnfTFvWGNEDd+ESx3ACmNbeAHilMURESkXR8 3iRt83bzL+H7xRpVEmLvUAbjJlf+4dzyftJSwTDquLsu+g4I45BDe1ki7ip9U06B EvgNZ0TKchNI2kn6I4R0XAYAdZyKRONWqYTPE3xEtweihLwOKYsKfQViSHkhYxuE upqMfsSzpT2ivqMb5myFU8JbG6jZZGTguAZ40MQT073gckgFoFfWjAtzR0fWa/Cy VJ79fWIfOXrRsc76UDBeDuJ3CFEliFMSzDJWwglxlp9JX6ckfHH0Vwfmj9NPcuRw AeAkI7Xh+emNKftJzNtC+6Ba7jMhMLLDBoe1r3NQYK1BFg/JRtkGCja3UAswotXH hEYMicbMnkhOGEKxjKL0jbl33XKKAVq3pens2tT0QIz3Xqzh9iIcceCnv4MsddK9 MPU8yfQYcj6eNxVBLofhuRGURMK4BpQzj2Rxg03G3dRpFuNEwneUrx64q8lEv4Y5 EWSFxOoBPEpooiMCoboZ/A== =/0m2 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190927' into staging target-arm queue: * Fix the CBAR register implementation for Cortex-A53, Cortex-A57, Cortex-A72 * Fix direct booting of Linux kernels on emulated CPUs which have an AArch32 EL3 (incorrect NSACR settings meant they could not access the FPU) * semihosting cleanup: do more work at translate time and less work at runtime # gpg: Signature made Fri 27 Sep 2019 15:32:43 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20190927: hw/arm/boot: Use the IEC binary prefix definitions hw/arm/boot.c: Set NSACR.{CP11,CP10} for NS kernel boots tests/tcg: add linux-user semihosting smoke test for ARM target/arm: remove run-time semihosting checks for linux-user target/arm: remove run time semihosting checks target/arm: handle A-profile semihosting at translate time target/arm: handle M-profile semihosting at translate time tests/tcg: clean-up some comments after the de-tangling target/arm: fix CBAR register for AArch64 CPUs Signed-off-by: Peter Maydell <peter.maydell@linaro.org> # Conflicts: # tests/tcg/arm/Makefile.target
This commit is contained in:
commit
786d36ad41
@ -575,7 +575,7 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (scells < 2 && binfo->ram_size >= (1ULL << 32)) {
|
||||
if (scells < 2 && binfo->ram_size >= 4 * GiB) {
|
||||
/* This is user error so deserves a friendlier error message
|
||||
* than the failure of setprop_sized_cells would provide
|
||||
*/
|
||||
@ -754,6 +754,8 @@ static void do_cpu_reset(void *opaque)
|
||||
(cs != first_cpu || !info->secure_board_setup)) {
|
||||
/* Linux expects non-secure state */
|
||||
env->cp15.scr_el3 |= SCR_NS;
|
||||
/* Set NSACR.{CP11,CP10} so NS can access the FPU */
|
||||
env->cp15.nsacr |= 3 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1095,7 +1097,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
* we might still make a bad choice here.
|
||||
*/
|
||||
info->initrd_start = info->loader_start +
|
||||
MIN(info->ram_size / 2, 128 * 1024 * 1024);
|
||||
MIN(info->ram_size / 2, 128 * MiB);
|
||||
if (image_high_addr) {
|
||||
info->initrd_start = MAX(info->initrd_start, image_high_addr);
|
||||
}
|
||||
@ -1155,13 +1157,13 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
*
|
||||
* Let's play safe and prealign it to 2MB to give us some space.
|
||||
*/
|
||||
align = 2 * 1024 * 1024;
|
||||
align = 2 * MiB;
|
||||
} else {
|
||||
/*
|
||||
* Some 32bit kernels will trash anything in the 4K page the
|
||||
* initrd ends in, so make sure the DTB isn't caught up in that.
|
||||
*/
|
||||
align = 4096;
|
||||
align = 4 * KiB;
|
||||
}
|
||||
|
||||
/* Place the DTB after the initrd in memory with alignment. */
|
||||
@ -1178,7 +1180,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
info->loader_start + KERNEL_ARGS_ADDR;
|
||||
fixupcontext[FIXUP_ARGPTR_HI] =
|
||||
(info->loader_start + KERNEL_ARGS_ADDR) >> 32;
|
||||
if (info->ram_size >= (1ULL << 32)) {
|
||||
if (info->ram_size >= 4 * GiB) {
|
||||
error_report("RAM size must be less than 4GB to boot"
|
||||
" Linux kernel using ATAGS (try passing a device tree"
|
||||
" using -dtb)");
|
||||
|
@ -325,9 +325,6 @@ void cpu_loop(CPUARMState *env)
|
||||
|
||||
if (n == ARM_NR_cacheflush) {
|
||||
/* nop */
|
||||
} else if (n == ARM_NR_semihosting
|
||||
|| n == ARM_NR_thumb_semihosting) {
|
||||
env->regs[0] = do_arm_semihosting (env);
|
||||
} else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
|
||||
/* linux syscall */
|
||||
if (env->thumb || n == 0) {
|
||||
|
@ -18,9 +18,6 @@ struct target_pt_regs {
|
||||
#define ARM_NR_set_tls (ARM_NR_BASE + 5)
|
||||
#define ARM_NR_get_tls (ARM_NR_BASE + 6)
|
||||
|
||||
#define ARM_NR_semihosting 0x123456
|
||||
#define ARM_NR_thumb_semihosting 0xAB
|
||||
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
#define UNAME_MACHINE "armv5teb"
|
||||
#else
|
||||
|
@ -6733,6 +6733,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
}
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_CBAR)) {
|
||||
/*
|
||||
* CBAR is IMPDEF, but common on Arm Cortex-A implementations.
|
||||
* There are two flavours:
|
||||
* (1) older 32-bit only cores have a simple 32-bit CBAR
|
||||
* (2) 64-bit cores have a 64-bit CBAR visible to AArch64, plus a
|
||||
* 32-bit register visible to AArch32 at a different encoding
|
||||
* to the "flavour 1" register and with the bits rearranged to
|
||||
* be able to squash a 64-bit address into the 32-bit view.
|
||||
* We distinguish the two via the ARM_FEATURE_AARCH64 flag, but
|
||||
* in future if we support AArch32-only configs of some of the
|
||||
* AArch64 cores we might need to add a specific feature flag
|
||||
* to indicate cores with "flavour 2" CBAR.
|
||||
*/
|
||||
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||
/* 32 bit view is [31:18] 0...0 [43:32]. */
|
||||
uint32_t cbar32 = (extract64(cpu->reset_cbar, 18, 14) << 18)
|
||||
@ -6740,12 +6753,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
ARMCPRegInfo cbar_reginfo[] = {
|
||||
{ .name = "CBAR",
|
||||
.type = ARM_CP_CONST,
|
||||
.cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0,
|
||||
.access = PL1_R, .resetvalue = cpu->reset_cbar },
|
||||
.cp = 15, .crn = 15, .crm = 3, .opc1 = 1, .opc2 = 0,
|
||||
.access = PL1_R, .resetvalue = cbar32 },
|
||||
{ .name = "CBAR_EL1", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_CONST,
|
||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0,
|
||||
.access = PL1_R, .resetvalue = cbar32 },
|
||||
.access = PL1_R, .resetvalue = cpu->reset_cbar },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
/* We don't implement a r/w 64 bit CBAR currently */
|
||||
@ -8339,88 +8352,32 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
|
||||
new_el, env->pc, pstate_read(env));
|
||||
}
|
||||
|
||||
static inline bool check_for_semihosting(CPUState *cs)
|
||||
{
|
||||
/*
|
||||
* Do semihosting call and set the appropriate return value. All the
|
||||
* permission and validity checks have been done at translate time.
|
||||
*
|
||||
* We only see semihosting exceptions in TCG only as they are not
|
||||
* trapped to the hypervisor in KVM.
|
||||
*/
|
||||
#ifdef CONFIG_TCG
|
||||
/* Check whether this exception is a semihosting call; if so
|
||||
* then handle it and return true; otherwise return false.
|
||||
*/
|
||||
static void handle_semihosting(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
if (is_a64(env)) {
|
||||
if (cs->exception_index == EXCP_SEMIHOST) {
|
||||
/* This is always the 64-bit semihosting exception.
|
||||
* The "is this usermode" and "is semihosting enabled"
|
||||
* checks have been done at translate time.
|
||||
*/
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%" PRIx64 "\n",
|
||||
env->xregs[0]);
|
||||
env->xregs[0] = do_arm_semihosting(env);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%" PRIx64 "\n",
|
||||
env->xregs[0]);
|
||||
env->xregs[0] = do_arm_semihosting(env);
|
||||
} else {
|
||||
uint32_t imm;
|
||||
|
||||
/* Only intercept calls from privileged modes, to provide some
|
||||
* semblance of security.
|
||||
*/
|
||||
if (cs->exception_index != EXCP_SEMIHOST &&
|
||||
(!semihosting_enabled() ||
|
||||
((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_SEMIHOST:
|
||||
/* This is always a semihosting call; the "is this usermode"
|
||||
* and "is semihosting enabled" checks have been done at
|
||||
* translate time.
|
||||
*/
|
||||
break;
|
||||
case EXCP_SWI:
|
||||
/* Check for semihosting interrupt. */
|
||||
if (env->thumb) {
|
||||
imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env))
|
||||
& 0xff;
|
||||
if (imm == 0xab) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env))
|
||||
& 0xffffff;
|
||||
if (imm == 0x123456) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case EXCP_BKPT:
|
||||
/* See if this is a semihosting syscall. */
|
||||
if (env->thumb) {
|
||||
imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env))
|
||||
& 0xff;
|
||||
if (imm == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle a CPU exception for A and R profile CPUs.
|
||||
* Do any appropriate logging, handle PSCI calls, and then hand off
|
||||
@ -8451,13 +8408,17 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Semihosting semantics depend on the register width of the
|
||||
* code that caused the exception, not the target exception level,
|
||||
* so must be handled here.
|
||||
/*
|
||||
* Semihosting semantics depend on the register width of the code
|
||||
* that caused the exception, not the target exception level, so
|
||||
* must be handled here.
|
||||
*/
|
||||
if (check_for_semihosting(cs)) {
|
||||
#ifdef CONFIG_TCG
|
||||
if (cs->exception_index == EXCP_SEMIHOST) {
|
||||
handle_semihosting(cs);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Hooks may change global state so BQL should be held, also the
|
||||
* BQL needs to be held for any modification of
|
||||
|
@ -2114,19 +2114,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
return;
|
||||
case EXCP_BKPT:
|
||||
if (semihosting_enabled()) {
|
||||
int nr;
|
||||
nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
|
||||
if (nr == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"...handling as semihosting call 0x%x\n",
|
||||
env->regs[0]);
|
||||
env->regs[0] = do_arm_semihosting(env);
|
||||
return;
|
||||
}
|
||||
}
|
||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
||||
break;
|
||||
case EXCP_IRQ:
|
||||
|
@ -8424,7 +8424,16 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
|
||||
if (!ENABLE_ARCH_5) {
|
||||
return false;
|
||||
}
|
||||
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
|
||||
if (arm_dc_feature(s, ARM_FEATURE_M) &&
|
||||
semihosting_enabled() &&
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
!IS_USER(s) &&
|
||||
#endif
|
||||
(a->imm == 0xab)) {
|
||||
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
|
||||
} else {
|
||||
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -10213,14 +10222,25 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
|
||||
}
|
||||
|
||||
/*
|
||||
* Supervisor call
|
||||
* Supervisor call - both T32 & A32 come here so we need to check
|
||||
* which mode we are in when checking for semihosting.
|
||||
*/
|
||||
|
||||
static bool trans_SVC(DisasContext *s, arg_SVC *a)
|
||||
{
|
||||
gen_set_pc_im(s, s->base.pc_next);
|
||||
s->svc_imm = a->imm;
|
||||
s->base.is_jmp = DISAS_SWI;
|
||||
const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456;
|
||||
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled() &&
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
!IS_USER(s) &&
|
||||
#endif
|
||||
(a->imm == semihost_imm)) {
|
||||
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
|
||||
} else {
|
||||
gen_set_pc_im(s, s->base.pc_next);
|
||||
s->svc_imm = a->imm;
|
||||
s->base.is_jmp = DISAS_SWI;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -21,4 +21,9 @@ run-fcvt: fcvt
|
||||
AARCH64_TESTS += pauth-1 pauth-2
|
||||
run-pauth-%: QEMU_OPTS += -cpu max
|
||||
|
||||
# Semihosting smoke test for linux-user
|
||||
AARCH64_TESTS += semihosting
|
||||
run-semihosting: semihosting
|
||||
$(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)")
|
||||
|
||||
TESTS += $(AARCH64_TESTS)
|
||||
|
@ -8,7 +8,6 @@ ARM_SRC=$(SRC_PATH)/tests/tcg/arm
|
||||
# Set search path for all sources
|
||||
VPATH += $(ARM_SRC)
|
||||
|
||||
# Multiarch Tests
|
||||
float_madds: CFLAGS+=-mfpu=neon-vfpv4
|
||||
|
||||
# Basic Hello World
|
||||
@ -30,6 +29,11 @@ run-fcvt: fcvt
|
||||
$(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)")
|
||||
$(call diff-out,fcvt,$(ARM_SRC)/fcvt.ref)
|
||||
|
||||
# Semihosting smoke test for linux-user
|
||||
ARM_TESTS += semihosting
|
||||
run-semihosting: semihosting
|
||||
$(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)")
|
||||
|
||||
TESTS += $(ARM_TESTS)
|
||||
|
||||
# On ARM Linux only supports 4k pages
|
||||
|
45
tests/tcg/arm/semihosting.c
Normal file
45
tests/tcg/arm/semihosting.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* linux-user semihosting checks
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Written by Alex Bennée <alex.bennee@linaro.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SYS_WRITE0 0x04
|
||||
#define SYS_REPORTEXC 0x18
|
||||
|
||||
void __semi_call(uintptr_t type, uintptr_t arg0)
|
||||
{
|
||||
#if defined(__arm__)
|
||||
register uintptr_t t asm("r0") = type;
|
||||
register uintptr_t a0 asm("r1") = arg0;
|
||||
asm("svc 0xab"
|
||||
: /* no return */
|
||||
: "r" (t), "r" (a0));
|
||||
#else
|
||||
register uintptr_t t asm("x0") = type;
|
||||
register uintptr_t a0 asm("x1") = arg0;
|
||||
asm("hlt 0xf000"
|
||||
: /* no return */
|
||||
: "r" (t), "r" (a0));
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[argc])
|
||||
{
|
||||
#if defined(__arm__)
|
||||
uintptr_t exit_code = 0x20026;
|
||||
#else
|
||||
uintptr_t exit_block[2] = {0x20026, 0};
|
||||
uintptr_t exit_code = (uintptr_t) &exit_block;
|
||||
#endif
|
||||
|
||||
__semi_call(SYS_WRITE0, (uintptr_t) "Hello World");
|
||||
__semi_call(SYS_REPORTEXC, exit_code);
|
||||
/* if we get here we failed */
|
||||
return -1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user