mirror of https://gitee.com/openkylin/qemu.git
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;
|
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
|
/* This is user error so deserves a friendlier error message
|
||||||
* than the failure of setprop_sized_cells would provide
|
* 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)) {
|
(cs != first_cpu || !info->secure_board_setup)) {
|
||||||
/* Linux expects non-secure state */
|
/* Linux expects non-secure state */
|
||||||
env->cp15.scr_el3 |= SCR_NS;
|
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.
|
* we might still make a bad choice here.
|
||||||
*/
|
*/
|
||||||
info->initrd_start = info->loader_start +
|
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) {
|
if (image_high_addr) {
|
||||||
info->initrd_start = MAX(info->initrd_start, 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.
|
* Let's play safe and prealign it to 2MB to give us some space.
|
||||||
*/
|
*/
|
||||||
align = 2 * 1024 * 1024;
|
align = 2 * MiB;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Some 32bit kernels will trash anything in the 4K page the
|
* 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.
|
* 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. */
|
/* 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;
|
info->loader_start + KERNEL_ARGS_ADDR;
|
||||||
fixupcontext[FIXUP_ARGPTR_HI] =
|
fixupcontext[FIXUP_ARGPTR_HI] =
|
||||||
(info->loader_start + KERNEL_ARGS_ADDR) >> 32;
|
(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"
|
error_report("RAM size must be less than 4GB to boot"
|
||||||
" Linux kernel using ATAGS (try passing a device tree"
|
" Linux kernel using ATAGS (try passing a device tree"
|
||||||
" using -dtb)");
|
" using -dtb)");
|
||||||
|
|
|
@ -325,9 +325,6 @@ void cpu_loop(CPUARMState *env)
|
||||||
|
|
||||||
if (n == ARM_NR_cacheflush) {
|
if (n == ARM_NR_cacheflush) {
|
||||||
/* nop */
|
/* 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) {
|
} else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
|
||||||
/* linux syscall */
|
/* linux syscall */
|
||||||
if (env->thumb || n == 0) {
|
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_set_tls (ARM_NR_BASE + 5)
|
||||||
#define ARM_NR_get_tls (ARM_NR_BASE + 6)
|
#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)
|
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||||
#define UNAME_MACHINE "armv5teb"
|
#define UNAME_MACHINE "armv5teb"
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -6733,6 +6733,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_CBAR)) {
|
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)) {
|
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||||
/* 32 bit view is [31:18] 0...0 [43:32]. */
|
/* 32 bit view is [31:18] 0...0 [43:32]. */
|
||||||
uint32_t cbar32 = (extract64(cpu->reset_cbar, 18, 14) << 18)
|
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[] = {
|
ARMCPRegInfo cbar_reginfo[] = {
|
||||||
{ .name = "CBAR",
|
{ .name = "CBAR",
|
||||||
.type = ARM_CP_CONST,
|
.type = ARM_CP_CONST,
|
||||||
.cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0,
|
.cp = 15, .crn = 15, .crm = 3, .opc1 = 1, .opc2 = 0,
|
||||||
.access = PL1_R, .resetvalue = cpu->reset_cbar },
|
.access = PL1_R, .resetvalue = cbar32 },
|
||||||
{ .name = "CBAR_EL1", .state = ARM_CP_STATE_AA64,
|
{ .name = "CBAR_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.type = ARM_CP_CONST,
|
.type = ARM_CP_CONST,
|
||||||
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0,
|
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0,
|
||||||
.access = PL1_R, .resetvalue = cbar32 },
|
.access = PL1_R, .resetvalue = cpu->reset_cbar },
|
||||||
REGINFO_SENTINEL
|
REGINFO_SENTINEL
|
||||||
};
|
};
|
||||||
/* We don't implement a r/w 64 bit CBAR currently */
|
/* 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));
|
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
|
||||||
#ifdef CONFIG_TCG
|
* permission and validity checks have been done at translate time.
|
||||||
/* Check whether this exception is a semihosting call; if so
|
*
|
||||||
* then handle it and return true; otherwise return false.
|
* We only see semihosting exceptions in TCG only as they are not
|
||||||
|
* trapped to the hypervisor in KVM.
|
||||||
*/
|
*/
|
||||||
|
#ifdef CONFIG_TCG
|
||||||
|
static void handle_semihosting(CPUState *cs)
|
||||||
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
|
|
||||||
if (is_a64(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,
|
qemu_log_mask(CPU_LOG_INT,
|
||||||
"...handling as semihosting call 0x%" PRIx64 "\n",
|
"...handling as semihosting call 0x%" PRIx64 "\n",
|
||||||
env->xregs[0]);
|
env->xregs[0]);
|
||||||
env->xregs[0] = do_arm_semihosting(env);
|
env->xregs[0] = do_arm_semihosting(env);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
} 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,
|
qemu_log_mask(CPU_LOG_INT,
|
||||||
"...handling as semihosting call 0x%x\n",
|
"...handling as semihosting call 0x%x\n",
|
||||||
env->regs[0]);
|
env->regs[0]);
|
||||||
env->regs[0] = do_arm_semihosting(env);
|
env->regs[0] = do_arm_semihosting(env);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Handle a CPU exception for A and R profile CPUs.
|
/* Handle a CPU exception for A and R profile CPUs.
|
||||||
* Do any appropriate logging, handle PSCI calls, and then hand off
|
* Do any appropriate logging, handle PSCI calls, and then hand off
|
||||||
|
@ -8451,13 +8408,17 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Semihosting semantics depend on the register width of the
|
/*
|
||||||
* code that caused the exception, not the target exception level,
|
* Semihosting semantics depend on the register width of the code
|
||||||
* so must be handled here.
|
* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Hooks may change global state so BQL should be held, also the
|
/* Hooks may change global state so BQL should be held, also the
|
||||||
* BQL needs to be held for any modification of
|
* BQL needs to be held for any modification of
|
||||||
|
|
|
@ -2114,19 +2114,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EXCP_BKPT:
|
case EXCP_SEMIHOST:
|
||||||
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,
|
qemu_log_mask(CPU_LOG_INT,
|
||||||
"...handling as semihosting call 0x%x\n",
|
"...handling as semihosting call 0x%x\n",
|
||||||
env->regs[0]);
|
env->regs[0]);
|
||||||
env->regs[0] = do_arm_semihosting(env);
|
env->regs[0] = do_arm_semihosting(env);
|
||||||
return;
|
return;
|
||||||
}
|
case EXCP_BKPT:
|
||||||
}
|
|
||||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
|
||||||
break;
|
break;
|
||||||
case EXCP_IRQ:
|
case EXCP_IRQ:
|
||||||
|
|
|
@ -8424,7 +8424,16 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
|
||||||
if (!ENABLE_ARCH_5) {
|
if (!ENABLE_ARCH_5) {
|
||||||
return false;
|
return 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));
|
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
|
||||||
|
}
|
||||||
return true;
|
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)
|
static bool trans_SVC(DisasContext *s, arg_SVC *a)
|
||||||
{
|
{
|
||||||
|
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);
|
gen_set_pc_im(s, s->base.pc_next);
|
||||||
s->svc_imm = a->imm;
|
s->svc_imm = a->imm;
|
||||||
s->base.is_jmp = DISAS_SWI;
|
s->base.is_jmp = DISAS_SWI;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,4 +21,9 @@ run-fcvt: fcvt
|
||||||
AARCH64_TESTS += pauth-1 pauth-2
|
AARCH64_TESTS += pauth-1 pauth-2
|
||||||
run-pauth-%: QEMU_OPTS += -cpu max
|
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)
|
TESTS += $(AARCH64_TESTS)
|
||||||
|
|
|
@ -8,7 +8,6 @@ ARM_SRC=$(SRC_PATH)/tests/tcg/arm
|
||||||
# Set search path for all sources
|
# Set search path for all sources
|
||||||
VPATH += $(ARM_SRC)
|
VPATH += $(ARM_SRC)
|
||||||
|
|
||||||
# Multiarch Tests
|
|
||||||
float_madds: CFLAGS+=-mfpu=neon-vfpv4
|
float_madds: CFLAGS+=-mfpu=neon-vfpv4
|
||||||
|
|
||||||
# Basic Hello World
|
# Basic Hello World
|
||||||
|
@ -30,6 +29,11 @@ run-fcvt: fcvt
|
||||||
$(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)")
|
$(call run-test,fcvt,$(QEMU) $<,"$< on $(TARGET_NAME)")
|
||||||
$(call diff-out,fcvt,$(ARM_SRC)/fcvt.ref)
|
$(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)
|
TESTS += $(ARM_TESTS)
|
||||||
|
|
||||||
# On ARM Linux only supports 4k pages
|
# On ARM Linux only supports 4k pages
|
||||||
|
|
|
@ -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