Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-2…
Browse files Browse the repository at this point in the history
…0190927' 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
  • Loading branch information
pm215 committed Sep 30, 2019
2 parents 1e39638 + e4e3485 commit 786d36a
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 106 deletions.
12 changes: 7 additions & 5 deletions hw/arm/boot.c
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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. */
Expand All @@ -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)");
Expand Down
3 changes: 0 additions & 3 deletions linux-user/arm/cpu_loop.c
Expand Up @@ -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) {
Expand Down
3 changes: 0 additions & 3 deletions linux-user/arm/target_syscall.h
Expand Up @@ -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
Expand Down
115 changes: 38 additions & 77 deletions target/arm/helper.c
Expand Up @@ -6733,19 +6733,32 @@ 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)
| extract64(cpu->reset_cbar, 32, 12);
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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
18 changes: 6 additions & 12 deletions target/arm/m_helper.c
Expand Up @@ -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:
Expand Down
30 changes: 25 additions & 5 deletions target/arm/translate.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions tests/tcg/aarch64/Makefile.target
Expand Up @@ -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)
6 changes: 5 additions & 1 deletion tests/tcg/arm/Makefile.target
Expand Up @@ -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
Expand All @@ -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
Expand Down
45 changes: 45 additions & 0 deletions tests/tcg/arm/semihosting.c
@@ -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;
}

0 comments on commit 786d36a

Please sign in to comment.