From 7cd6de3bb1ca55dfa8f53fb9894803eb33f497b3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Oct 2015 12:00:50 +0000 Subject: [PATCH 01/27] target-arm: Fix "no 64-bit EL2" assumption in arm_excp_unmasked() The code in arm_excp_unmasked() suppresses the ability of PSTATE.AIF to mask exceptions from a lower EL targeting EL2 or EL3 if the CPU is 64-bit. This is correct for a target of EL3, but not correct for targeting EL2. Further, we go to some effort to calculate scr and hcr values which are not used at all for the 64-bit CPU case. Rearrange the code to correctly implement the 64-bit CPU logic and keep the hcr/scr calculations in the 32-bit CPU codepath. Signed-off-by: Peter Maydell Message-id: 1444327729-4120-1-git-send-email-peter.maydell@linaro.org Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias --- target-arm/cpu.h | 82 ++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 3daa7f58f9..a2712057ab 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -1525,8 +1525,6 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, CPUARMState *env = cs->env_ptr; unsigned int cur_el = arm_current_el(env); bool secure = arm_is_secure(env); - bool scr; - bool hcr; bool pstate_unmasked; int8_t unmasked = 0; @@ -1540,31 +1538,10 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, switch (excp_idx) { case EXCP_FIQ: - /* If FIQs are routed to EL3 or EL2 then there are cases where we - * override the CPSR.F in determining if the exception is masked or - * not. If neither of these are set then we fall back to the CPSR.F - * setting otherwise we further assess the state below. - */ - hcr = (env->cp15.hcr_el2 & HCR_FMO); - scr = (env->cp15.scr_el3 & SCR_FIQ); - - /* When EL3 is 32-bit, the SCR.FW bit controls whether the CPSR.F bit - * masks FIQ interrupts when taken in non-secure state. If SCR.FW is - * set then FIQs can be masked by CPSR.F when non-secure but only - * when FIQs are only routed to EL3. - */ - scr = scr && !((env->cp15.scr_el3 & SCR_FW) && !hcr); pstate_unmasked = !(env->daif & PSTATE_F); break; case EXCP_IRQ: - /* When EL3 execution state is 32-bit, if HCR.IMO is set then we may - * override the CPSR.I masking when in non-secure state. The SCR.IRQ - * setting has already been taken into consideration when setting the - * target EL, so it does not have a further affect here. - */ - hcr = (env->cp15.hcr_el2 & HCR_IMO); - scr = false; pstate_unmasked = !(env->daif & PSTATE_I); break; @@ -1589,13 +1566,58 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * interrupt. */ if ((target_el > cur_el) && (target_el != 1)) { - /* ARM_FEATURE_AARCH64 enabled means the highest EL is AArch64. - * This code currently assumes that EL2 is not implemented - * (and so that highest EL will be 3 and the target_el also 3). - */ - if (arm_feature(env, ARM_FEATURE_AARCH64) || - ((scr || hcr) && (!secure))) { - unmasked = 1; + /* Exceptions targeting a higher EL may not be maskable */ + if (arm_feature(env, ARM_FEATURE_AARCH64)) { + /* 64-bit masking rules are simple: exceptions to EL3 + * can't be masked, and exceptions to EL2 can only be + * masked from Secure state. The HCR and SCR settings + * don't affect the masking logic, only the interrupt routing. + */ + if (target_el == 3 || !secure) { + unmasked = 1; + } + } else { + /* The old 32-bit-only environment has a more complicated + * masking setup. HCR and SCR bits not only affect interrupt + * routing but also change the behaviour of masking. + */ + bool hcr, scr; + + switch (excp_idx) { + case EXCP_FIQ: + /* If FIQs are routed to EL3 or EL2 then there are cases where + * we override the CPSR.F in determining if the exception is + * masked or not. If neither of these are set then we fall back + * to the CPSR.F setting otherwise we further assess the state + * below. + */ + hcr = (env->cp15.hcr_el2 & HCR_FMO); + scr = (env->cp15.scr_el3 & SCR_FIQ); + + /* When EL3 is 32-bit, the SCR.FW bit controls whether the + * CPSR.F bit masks FIQ interrupts when taken in non-secure + * state. If SCR.FW is set then FIQs can be masked by CPSR.F + * when non-secure but only when FIQs are only routed to EL3. + */ + scr = scr && !((env->cp15.scr_el3 & SCR_FW) && !hcr); + break; + case EXCP_IRQ: + /* When EL3 execution state is 32-bit, if HCR.IMO is set then + * we may override the CPSR.I masking when in non-secure state. + * The SCR.IRQ setting has already been taken into consideration + * when setting the target EL, so it does not have a further + * affect here. + */ + hcr = (env->cp15.hcr_el2 & HCR_IMO); + scr = false; + break; + default: + g_assert_not_reached(); + } + + if ((scr || hcr) && !secure) { + unmasked = 1; + } } } From 541ebcd401ee47f3c1a3ce503ef5466b75e9d20a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 27 Oct 2015 12:00:50 +0000 Subject: [PATCH 02/27] target-arm/translate.c: Handle non-executable page-straddling Thumb insns When the memory we're trying to translate code from is not executable we have to turn this into a guest fault. In order to report the correct PC for this fault, and to make sure it is not reported until after any other possible faults for instructions earlier in execution, we must terminate TBs at the end of a page, in case the next instruction is in a non-executable page. This is simple for T16, A32 and A64 instructions, which are always aligned to their size. However T32 instructions may be 32-bits but only 16-aligned, so they can straddle a page boundary. Correct the condition that checks whether the next instruction will touch the following page, to ensure that if we're 2 bytes before the boundary and this insn is T32 then we end the TB. Reported-by: Pavel Dovgalyuk Reviewed-by: Laurent Desnogues Signed-off-by: Peter Maydell --- target-arm/translate.c | 45 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 9f1d740b4e..6be2c728f0 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -11179,6 +11179,35 @@ undef: default_exception_el(s)); } +static bool insn_crosses_page(CPUARMState *env, DisasContext *s) +{ + /* Return true if the insn at dc->pc might cross a page boundary. + * (False positives are OK, false negatives are not.) + */ + uint16_t insn; + + if ((s->pc & 3) == 0) { + /* At a 4-aligned address we can't be crossing a page */ + return false; + } + + /* This must be a Thumb insn */ + insn = arm_lduw_code(env, s->pc, s->bswap_code); + + if ((insn >> 11) >= 0x1d) { + /* Top five bits 0b11101 / 0b11110 / 0b11111 : this is the + * First half of a 32-bit Thumb insn. Thumb-1 cores might + * end up actually treating this as two 16-bit insns (see the + * code at the start of disas_thumb2_insn()) but we don't bother + * to check for that as it is unlikely, and false positives here + * are harmless. + */ + return true; + } + /* Definitely a 16-bit insn, can't be crossing a page. */ + return false; +} + /* generate intermediate code in gen_opc_buf and gen_opparam_buf for basic block 'tb'. */ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) @@ -11190,6 +11219,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) target_ulong next_page_start; int num_insns; int max_insns; + bool end_of_page; /* generate intermediate code */ @@ -11411,11 +11441,24 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) * Otherwise the subsequent code could get translated several times. * Also stop translation when a page boundary is reached. This * ensures prefetch aborts occur at the right place. */ + + /* We want to stop the TB if the next insn starts in a new page, + * or if it spans between this page and the next. This means that + * if we're looking at the last halfword in the page we need to + * see if it's a 16-bit Thumb insn (which will fit in this TB) + * or a 32-bit Thumb insn (which won't). + * This is to avoid generating a silly TB with a single 16-bit insn + * in it at the end of this page (which would execute correctly + * but isn't very efficient). + */ + end_of_page = (dc->pc >= next_page_start) || + ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc)); + } while (!dc->is_jmp && !tcg_op_buf_full() && !cs->singlestep_enabled && !singlestep && !dc->ss_active && - dc->pc < next_page_start && + !end_of_page && num_insns < max_insns); if (tb->cflags & CF_LAST_IO) { From b876452507d0b719cff0b478efafb34ac41db683 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Tue, 27 Oct 2015 12:00:50 +0000 Subject: [PATCH 03/27] target-arm: Add support for SPSR_(ABT|UND|IRQ|FIQ) Signed-off-by: Soren Brinkmann Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index e7fda37466..aba5025403 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3288,6 +3288,22 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .type = ARM_CP_ALIAS, .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0, .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[6]) }, + { .name = "SPSR_IRQ", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, + .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 0, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[4]) }, + { .name = "SPSR_ABT", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, + .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 1, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[2]) }, + { .name = "SPSR_UND", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, + .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 2, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[3]) }, + { .name = "SPSR_FIQ", .state = ARM_CP_STATE_AA64, + .type = ARM_CP_ALIAS, + .opc0 = 3, .opc1 = 4, .crn = 4, .crm = 3, .opc2 = 3, + .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[5]) }, { .name = "VBAR_EL2", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0, .access = PL2_RW, .writefn = vbar_write, From 24182fbc19cbc7c387bb350a72e6b55f63ea1747 Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Tue, 27 Oct 2015 12:00:50 +0000 Subject: [PATCH 04/27] arm_gic_kvm: Disable live migration if not supported Currently, if the kernel does not have live migration API, the migration will still be attempted, but vGIC save/restore functions will just not do anything. This will result in a broken machine state. This patch fixes the problem by adding migration blocker if kernel API is not supported. Signed-off-by: Pavel Fedin Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gic_kvm.c | 22 +++++++++++----------- include/hw/intc/arm_gic_common.h | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index e8b2386908..0ceebbf87e 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -20,6 +20,7 @@ */ #include "hw/sysbus.h" +#include "migration/migration.h" #include "sysemu/kvm.h" #include "kvm_arm.h" #include "gic_internal.h" @@ -307,11 +308,6 @@ static void kvm_arm_gic_put(GICState *s) int num_cpu; int num_irq; - if (!kvm_arm_gic_can_save_restore(s)) { - DPRINTF("Cannot put kernel gic state, no kernel interface"); - return; - } - /* Note: We do the restore in a slightly different order than the save * (where the order doesn't matter and is simply ordered according to the * register offset values */ @@ -411,11 +407,6 @@ static void kvm_arm_gic_get(GICState *s) int i; int cpu; - if (!kvm_arm_gic_can_save_restore(s)) { - DPRINTF("Cannot get kernel gic state, no kernel interface"); - return; - } - /***************************************************************** * Distributor State */ @@ -503,7 +494,10 @@ static void kvm_arm_gic_reset(DeviceState *dev) KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s); kgc->parent_reset(dev); - kvm_arm_gic_put(s); + + if (kvm_arm_gic_can_save_restore(s)) { + kvm_arm_gic_put(s); + } } static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) @@ -573,6 +567,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, s->dev_fd); + + if (!kvm_arm_gic_can_save_restore(s)) { + error_setg(&s->migration_blocker, "This operating system kernel does " + "not support vGICv2 migration"); + migrate_add_blocker(s->migration_blocker); + } } static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 564a72b2cf..f4c349a2ef 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -111,6 +111,7 @@ typedef struct GICState { bool security_extn; bool irq_reset_nonsecure; /* configure IRQs as group 1 (NS) on reset? */ int dev_fd; /* kvm device fd if backed by kvm vgic support */ + Error *migration_blocker; } GICState; #define TYPE_ARM_GIC_COMMON "arm_gic_common" From 4b280b726a329a97db03323d8d03ed554f7872b8 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 27 Oct 2015 12:00:50 +0000 Subject: [PATCH 05/27] hw/arm/virt: don't use a15memmap directly We should always go through VirtBoardInfo when we need the memmap. To avoid using a15memmap directly, in this case, we need to defer the max-cpus check from class init time to instance init time. In class init we now use MAX_CPUMASK_BITS for max_cpus initialization, which is the maximum QEMU supports, and also, incidentally, the maximum KVM/gicv3 currently supports. Also, a nice side-effect of delaying the max-cpus check is that we now get more appropriate error messages for gicv2 machines that try to configure more than 123 cpus. Before this patch it would complain that the requested number of cpus was greater than 123, but for gicv2 configs, it should complain that the number is greater than 8. Signed-off-by: Andrew Jones Message-id: 1445189728-860-3-git-send-email-drjones@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 5d38c47444..77d9267599 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -923,7 +923,7 @@ static void machvirt_init(MachineState *machine) qemu_irq pic[NUM_IRQS]; MemoryRegion *sysmem = get_system_memory(); int gic_version = vms->gic_version; - int n; + int n, max_cpus; MemoryRegion *ram = g_new(MemoryRegion, 1); const char *cpu_model = machine->cpu_model; VirtBoardInfo *vbi; @@ -957,6 +957,22 @@ static void machvirt_init(MachineState *machine) exit(1); } + /* The maximum number of CPUs depends on the GIC version, or on how + * many redistributors we can fit into the memory map. + */ + if (gic_version == 3) { + max_cpus = vbi->memmap[VIRT_GIC_REDIST].size / 0x20000; + } else { + max_cpus = GIC_NCPU; + } + + if (smp_cpus > max_cpus) { + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " + "supported by machine 'mach-virt' (%d)", + smp_cpus, max_cpus); + exit(1); + } + vbi->smp_cpus = smp_cpus; if (machine->ram_size > vbi->memmap[VIRT_MEM].size) { @@ -1155,10 +1171,11 @@ static void virt_class_init(ObjectClass *oc, void *data) mc->desc = "ARM Virtual Machine", mc->init = machvirt_init; - /* Our maximum number of CPUs depends on how many redistributors - * we can fit into memory map + /* Start max_cpus at the maximum QEMU supports. We'll further restrict + * it later in machvirt_init, where we have more information about the + * configuration of the particular instance. */ - mc->max_cpus = a15memmap[VIRT_GIC_REDIST].size / 0x20000; + mc->max_cpus = MAX_CPUMASK_BITS; mc->has_dynamic_sysbus = true; mc->block_default_type = IF_VIRTIO; mc->no_cdrom = 1; From 8ccce77c04a23a1451b6e149930e66b6eef75926 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:06 +0100 Subject: [PATCH 06/27] i.MX: Standardize i.MX serial debug. The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message We also replace IPRINTF with qemu_log_mask(). The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 47b8759b251d356c633faf7ea34f897f340aea4e.1445781957.git.jcd@tribudubois.net [PMM: Drop attempt to print the ram_addr of a memory region in one DPRINTF, which (a) was using the wrong format string so didn't build on 32-bit and (b) was incorrectly looking at a private field of a MemoryRegion struct] Signed-off-by: Peter Maydell --- hw/char/imx_serial.c | 50 +++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index f0c4c722d6..f30f9c24be 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -22,25 +22,17 @@ #include "sysemu/sysemu.h" #include "sysemu/char.h" -//#define DEBUG_SERIAL 1 -#ifdef DEBUG_SERIAL -#define DPRINTF(fmt, args...) \ -do { printf("%s: " fmt , TYPE_IMX_SERIAL, ##args); } while (0) -#else -#define DPRINTF(fmt, args...) do {} while (0) +#ifndef DEBUG_IMX_UART +#define DEBUG_IMX_UART 0 #endif -/* - * Define to 1 for messages about attempts to - * access unimplemented registers or similar. - */ -//#define DEBUG_IMPLEMENTATION 1 -#ifdef DEBUG_IMPLEMENTATION -# define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt, TYPE_IMX_SERIAL, ##args); } while (0) -#else -# define IPRINTF(fmt, args...) do {} while (0) -#endif +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_UART) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SERIAL, \ + __func__, ##args); \ + } \ + } while (0) static const VMStateDescription vmstate_imx_serial = { .name = TYPE_IMX_SERIAL, @@ -115,7 +107,8 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset, IMXSerialState *s = (IMXSerialState *)opaque; uint32_t c; - DPRINTF("read(offset=%x)\n", offset >> 2); + DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset); + switch (offset >> 2) { case 0x0: /* URXD */ c = s->readbuff; @@ -167,7 +160,8 @@ static uint64_t imx_serial_read(void *opaque, hwaddr offset, return 0x0; /* TODO */ default: - IPRINTF("%s: bad offset: 0x%x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); return 0; } } @@ -178,9 +172,8 @@ static void imx_serial_write(void *opaque, hwaddr offset, IMXSerialState *s = (IMXSerialState *)opaque; unsigned char ch; - DPRINTF("write(offset=%x, value = %x) to %s\n", - offset >> 2, - (unsigned int)value, s->chr ? s->chr->label : "NODEV"); + DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n", + offset, (unsigned int)value, s->chr ? s->chr->label : "NODEV"); switch (offset >> 2) { case 0x10: /* UTXD */ @@ -198,7 +191,9 @@ static void imx_serial_write(void *opaque, hwaddr offset, case 0x20: /* UCR1 */ s->ucr1 = value & 0xffff; + DPRINTF("write(ucr1=%x)\n", (unsigned int)value); + imx_update(s); break; @@ -266,12 +261,14 @@ static void imx_serial_write(void *opaque, hwaddr offset, case 0x2d: /* UTS1 */ case 0x23: /* UCR4 */ - IPRINTF("Unimplemented Register %x written to\n", offset >> 2); + qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%" + HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); /* TODO */ break; default: - IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset); } } @@ -284,7 +281,9 @@ static int imx_can_receive(void *opaque) static void imx_put_data(void *opaque, uint32_t value) { IMXSerialState *s = (IMXSerialState *)opaque; + DPRINTF("received char\n"); + s->usr1 |= USR1_RRDY; s->usr2 |= USR2_RDR; s->uts1 &= ~UTS1_RXEMPTY; @@ -319,8 +318,7 @@ static void imx_serial_realize(DeviceState *dev, Error **errp) qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive, imx_event, s); } else { - DPRINTF("No char dev for uart at 0x%lx\n", - (unsigned long)s->iomem.ram_addr); + DPRINTF("No char dev for uart\n"); } } From 564111257468bb772ad0b374dbbb0c969a554cfd Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:11 +0100 Subject: [PATCH 07/27] i.MX: Standardize i.MX GPIO debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message The qemu_log_mask() outputis following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 4f2007adcf0f579864bb4dd8a825824e0e9098b8.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/gpio/imx_gpio.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c index d56ffcd8d7..3170585a27 100644 --- a/hw/gpio/imx_gpio.c +++ b/hw/gpio/imx_gpio.c @@ -29,11 +29,12 @@ typedef enum IMXGPIOLevel { } IMXGPIOLevel; #define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_GPIO) { \ - fprintf(stderr, "%s: " fmt , __func__, ##args); \ - } \ - } while (0) + do { \ + if (DEBUG_IMX_GPIO) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPIO, \ + __func__, ##args); \ + } \ + } while (0) static const char *imx_gpio_reg_name(uint32_t reg) { @@ -176,19 +177,19 @@ static uint64_t imx_gpio_read(void *opaque, hwaddr offset, unsigned size) if (s->has_edge_sel) { reg_value = s->edge_sel; } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not " + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not " "present on this version of GPIO device\n", TYPE_IMX_GPIO, __func__); } break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n", - TYPE_IMX_GPIO, __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset); break; } - DPRINTF("(%s) = 0x%"PRIx32"\n", imx_gpio_reg_name(offset), reg_value); + DPRINTF("(%s) = 0x%" PRIx32 "\n", imx_gpio_reg_name(offset), reg_value); return reg_value; } @@ -198,7 +199,7 @@ static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value, { IMXGPIOState *s = IMX_GPIO(opaque); - DPRINTF("(%s, value = 0x%"PRIx32")\n", imx_gpio_reg_name(offset), + DPRINTF("(%s, value = 0x%" PRIx32 ")\n", imx_gpio_reg_name(offset), (uint32_t)value); switch (offset) { @@ -238,15 +239,15 @@ static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value, s->edge_sel = value; imx_gpio_set_all_int_lines(s); } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: EDGE_SEL register not " + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: EDGE_SEL register not " "present on this version of GPIO device\n", TYPE_IMX_GPIO, __func__); } break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad register at offset %d\n", - TYPE_IMX_GPIO, __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset); break; } From 3afcbb01bc1227bc3a3bade1804c449daf74b262 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:14 +0100 Subject: [PATCH 08/27] i.MX: Standardize i.MX I2C debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 328acfe6fc09a5afdbfbfd5220e0869fd5082660.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/i2c/imx_i2c.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c index 8474872e07..cb62c7a2c9 100644 --- a/hw/i2c/imx_i2c.c +++ b/hw/i2c/imx_i2c.c @@ -21,13 +21,17 @@ #include "hw/i2c/imx_i2c.h" #include "hw/i2c/i2c.h" -#ifndef IMX_I2C_DEBUG -#define IMX_I2C_DEBUG 0 +#ifndef DEBUG_IMX_I2C +#define DEBUG_IMX_I2C 0 #endif -#if IMX_I2C_DEBUG -#define DPRINT(fmt, args...) \ - do { fprintf(stderr, "%s: "fmt, __func__, ## args); } while (0) +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_I2C) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_I2C, \ + __func__, ##args); \ + } \ + } while (0) static const char *imx_i2c_get_regname(unsigned offset) { @@ -46,9 +50,6 @@ static const char *imx_i2c_get_regname(unsigned offset) return "[?]"; } } -#else -#define DPRINT(fmt, args...) do { } while (0) -#endif static inline bool imx_i2c_is_enabled(IMXI2CState *s) { @@ -121,11 +122,11 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset, if (s->address == ADDR_RESET) { /* something is wrong as the address is not set */ - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read " + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " "without specifying the slave address\n", TYPE_IMX_I2C, __func__); } else if (s->i2cr & I2CR_MTX) { - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Trying to read " + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " "but MTX is set\n", TYPE_IMX_I2C, __func__); } else { /* get the next byte */ @@ -134,7 +135,7 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset, if (ret >= 0) { imx_i2c_raise_interrupt(s); } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: read failed " + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed " "for device 0x%02x\n", TYPE_IMX_I2C, __func__, s->address); ret = 0xff; @@ -143,19 +144,19 @@ static uint64_t imx_i2c_read(void *opaque, hwaddr offset, s->i2dr_read = ret; } else { - qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n", + qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", TYPE_IMX_I2C, __func__); } break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", - TYPE_IMX_I2C, __func__, s->address); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset); value = 0; break; } - DPRINT("read %s [0x%02x] -> 0x%02x\n", imx_i2c_get_regname(offset), - (unsigned int)offset, value); + DPRINTF("read %s [0x%" HWADDR_PRIx "] -> 0x%02x\n", + imx_i2c_get_regname(offset), offset, value); return (uint64_t)value; } @@ -165,8 +166,8 @@ static void imx_i2c_write(void *opaque, hwaddr offset, { IMXI2CState *s = IMX_I2C(opaque); - DPRINT("write %s [0x%02x] <- 0x%02x\n", imx_i2c_get_regname(offset), - (unsigned int)offset, (int)value); + DPRINTF("write %s [0x%" HWADDR_PRIx "] <- 0x%02x\n", + imx_i2c_get_regname(offset), offset, (int)value); value &= 0xff; @@ -264,13 +265,13 @@ static void imx_i2c_write(void *opaque, hwaddr offset, } } } else { - qemu_log_mask(LOG_UNIMP, "%s[%s]: slave mode not implemented\n", + qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", TYPE_IMX_I2C, __func__); } break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", - TYPE_IMX_I2C, __func__, s->address); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset); break; } } From f50ed7853ad658407382dfe1da29f3c88d604592 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:17 +0100 Subject: [PATCH 09/27] i.MX: Standardize i.MX AVIC debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message We also replace IPRINTF with qemu_log_mask(). The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 29885ffea2577eaf2288c1d17fd87ee951748b49.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/intc/imx_avic.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index 96c376b6af..e0535ffc57 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -17,27 +17,17 @@ #include "hw/intc/imx_avic.h" -#define DEBUG_INT 1 -#undef DEBUG_INT /* comment out for debugging */ +#ifndef DEBUG_IMX_AVIC +#define DEBUG_IMX_AVIC 0 +#endif -#ifdef DEBUG_INT #define DPRINTF(fmt, args...) \ -do { printf("%s: " fmt , TYPE_IMX_AVIC, ##args); } while (0) -#else -#define DPRINTF(fmt, args...) do {} while (0) -#endif - -/* - * Define to 1 for messages about attempts to - * access unimplemented registers or similar. - */ -#define DEBUG_IMPLEMENTATION 1 -#if DEBUG_IMPLEMENTATION -# define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt, TYPE_IMX_AVIC, ##args); } while (0) -#else -# define IPRINTF(fmt, args...) do {} while (0) -#endif + do { \ + if (DEBUG_IMX_AVIC) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \ + __func__, ##args); \ + } \ + } while (0) static const VMStateDescription vmstate_imx_avic = { .name = TYPE_IMX_AVIC, @@ -115,8 +105,8 @@ static uint64_t imx_avic_read(void *opaque, { IMXAVICState *s = (IMXAVICState *)opaque; + DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset); - DPRINTF("read(offset = 0x%x)\n", offset >> 2); switch (offset >> 2) { case 0: /* INTCNTL */ return s->intcntl; @@ -213,7 +203,8 @@ static uint64_t imx_avic_read(void *opaque, return 0x4; default: - IPRINTF("%s: Bad offset 0x%x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset); return 0; } } @@ -225,13 +216,13 @@ static void imx_avic_write(void *opaque, hwaddr offset, /* Vector Registers not yet supported */ if (offset >= 0x100 && offset <= 0x2fc) { - IPRINTF("%s to vector register %d ignored\n", __func__, - (unsigned int)((offset - 0x100) >> 2)); + qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n", + TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2)); return; } - DPRINTF("%s(0x%x) = %x\n", __func__, - (unsigned int)offset>>2, (unsigned int)val); + DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val); + switch (offset >> 2) { case 0: /* Interrupt Control Register, INTCNTL */ s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM); @@ -305,7 +296,8 @@ static void imx_avic_write(void *opaque, hwaddr offset, return; default: - IPRINTF("%s: Bad offset %x\n", __func__, (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset); } imx_avic_update(s); } From 4a6aa0af8593ee135ef37867ae00109650b95638 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:19 +0100 Subject: [PATCH 10/27] i.MX: Standardize i.MX CCM debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message The qemu_log_mask() output is following the same format as the above debug. Adding some missing qemu_log_mask call for bad registers. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 293e08f31cbb4df84d58f693243e61e770c73b3a.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/misc/imx_ccm.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 2e19dbb1bb..4cc2bbc0ed 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -16,14 +16,18 @@ #define CKIH_FREQ 26000000 /* 26MHz crystal input */ #define CKIL_FREQ 32768 /* nominal 32khz clock */ -//#define DEBUG_CCM 1 -#ifdef DEBUG_CCM -#define DPRINTF(fmt, args...) \ -do { printf("%s: " fmt , TYPE_IMX_CCM, ##args); } while (0) -#else -#define DPRINTF(fmt, args...) do {} while (0) +#ifndef DEBUG_IMX_CCM +#define DEBUG_IMX_CCM 0 #endif +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_CCM) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_CCM, \ + __func__, ##args); \ + } \ + } while (0) + static int imx_ccm_post_load(void *opaque, int version_id); static const VMStateDescription vmstate_imx_ccm = { @@ -109,7 +113,7 @@ static void update_clocks(IMXCCMState *s) s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP)); s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG)); - DPRINTF("%s: mcu %uMHz, HSP %uMHz, IPG %uHz\n", __func__, + DPRINTF("mcu %uMHz, HSP %uMHz, IPG %uHz\n", s->mcu_clk_freq / 1000000, s->hsp_clk_freq / 1000000, s->ipg_clk_freq); @@ -135,7 +139,8 @@ static uint64_t imx_ccm_read(void *opaque, hwaddr offset, { IMXCCMState *s = (IMXCCMState *)opaque; - DPRINTF("%s(offset=%x)", __func__, offset >> 2); + DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset); + switch (offset >> 2) { case 0: /* CCMR */ DPRINTF(" ccmr = 0x%x\n", s->ccmr); @@ -166,9 +171,11 @@ static uint64_t imx_ccm_read(void *opaque, hwaddr offset, case 23: DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0); return s->pmcr0; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset); + return 0; } - DPRINTF(" return 0\n"); - return 0; } static void imx_ccm_write(void *opaque, hwaddr offset, @@ -176,8 +183,9 @@ static void imx_ccm_write(void *opaque, hwaddr offset, { IMXCCMState *s = (IMXCCMState *)opaque; - DPRINTF("%s(offset=%x, value = %x)\n", __func__, - offset >> 2, (unsigned int)value); + DPRINTF("(offset=0x%" HWADDR_PRIx ", value = 0x%x)\n", + offset, (unsigned int)value); + switch (offset >> 2) { case 0: s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff); @@ -205,6 +213,8 @@ static void imx_ccm_write(void *opaque, hwaddr offset, return; default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset); return; } update_clocks(s); From b72d8d257c187532194f2fca504afb568cd2a3bf Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:21 +0100 Subject: [PATCH 11/27] i.MX: Standardize i.MX FEC debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 57e565982db94fb433c32dfa17608888464d21de.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 725f3fa335..c50bf7ff34 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -27,31 +27,29 @@ /* For crc32 */ #include -#ifndef IMX_FEC_DEBUG -#define IMX_FEC_DEBUG 0 +#ifndef DEBUG_IMX_FEC +#define DEBUG_IMX_FEC 0 #endif -#ifndef IMX_PHY_DEBUG -#define IMX_PHY_DEBUG 0 -#endif - -#if IMX_FEC_DEBUG -#define FEC_PRINTF(fmt, ...) \ - do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \ - ## __VA_ARGS__); \ +#define FEC_PRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_FEC) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \ + __func__, ##args); \ + } \ } while (0) -#else -#define FEC_PRINTF(fmt, ...) do {} while (0) + +#ifndef DEBUG_IMX_PHY +#define DEBUG_IMX_PHY 0 #endif -#if IMX_PHY_DEBUG -#define PHY_PRINTF(fmt, ...) \ - do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \ - ## __VA_ARGS__); \ +#define PHY_PRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_PHY) { \ + fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \ + __func__, ##args); \ + } \ } while (0) -#else -#define PHY_PRINTF(fmt, ...) do {} while (0) -#endif static const VMStateDescription vmstate_imx_fec = { .name = TYPE_IMX_FEC, @@ -182,12 +180,12 @@ static uint32_t do_phy_read(IMXFECState *s, int reg) case 18: case 27: case 31: - qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n", + qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n", TYPE_IMX_FEC, __func__, reg); val = 0; break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", + qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", TYPE_IMX_FEC, __func__, reg); val = 0; break; @@ -230,11 +228,11 @@ static void do_phy_write(IMXFECState *s, int reg, uint32_t val) case 18: case 27: case 31: - qemu_log_mask(LOG_UNIMP, "%s.phy[%s]: reg %d not implemented\n", + qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n", TYPE_IMX_FEC, __func__, reg); break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s.phy[%s]: Bad address at offset %d\n", + qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", TYPE_IMX_FEC, __func__, reg); break; } @@ -357,7 +355,7 @@ static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size) { IMXFECState *s = IMX_FEC(opaque); - FEC_PRINTF("reading from @ 0x%03x\n", (int)addr); + FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr); switch (addr & 0x3ff) { case 0x004: @@ -417,8 +415,8 @@ static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size) case 0x308: return s->miigsk_enr; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", - TYPE_IMX_FEC, __func__, (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); return 0; } } @@ -428,7 +426,7 @@ static void imx_fec_write(void *opaque, hwaddr addr, { IMXFECState *s = IMX_FEC(opaque); - FEC_PRINTF("writing 0x%08x @ 0x%03x\n", (int)value, (int)addr); + FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr); switch (addr & 0x3ff) { case 0x004: /* EIR */ @@ -530,8 +528,8 @@ static void imx_fec_write(void *opaque, hwaddr addr, s->miigsk_enr = (value & 0x2) ? 0x6 : 0; break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", - TYPE_IMX_FEC, __func__, (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); break; } @@ -561,7 +559,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, FEC_PRINTF("len %d\n", (int)size); if (!s->rx_enabled) { - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n", + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", TYPE_IMX_FEC, __func__); return 0; } @@ -592,14 +590,16 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, * save the remainder for when more RX buffers are * available, or flag an error. */ - qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n", + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n", TYPE_IMX_FEC, __func__); break; } buf_len = (size <= s->emrbr) ? size : s->emrbr; bd.length = buf_len; size -= buf_len; - FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length); + + FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); + /* The last 4 bytes are the CRC. */ if (size < 4) { buf_len += size - 4; From 4929f6563c704dbd057524b38ee519b3a7c8dfe1 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:24 +0100 Subject: [PATCH 12/27] i.MX: Standardize i.MX EPIT debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message We also replace IPRINTF with qemu_log_mask(). The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: 5bbad71517ca728d8865f7b9f998baa0df022794.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/timer/imx_epit.c | 48 +++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index 9649851526..967be4ad27 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -16,8 +16,17 @@ #include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -#define DEBUG_TIMER 0 -#if DEBUG_TIMER +#ifndef DEBUG_IMX_EPIT +#define DEBUG_IMX_EPIT 0 +#endif + +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_EPIT) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_EPIT, \ + __func__, ##args); \ + } \ + } while (0) static char const *imx_epit_reg_name(uint32_t reg) { @@ -37,24 +46,6 @@ static char const *imx_epit_reg_name(uint32_t reg) } } -# define DPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt , __func__, ##args); } while (0) -#else -# define DPRINTF(fmt, args...) do {} while (0) -#endif - -/* - * Define to 1 for messages about attempts to - * access unimplemented registers or similar. - */ -#define DEBUG_IMPLEMENTATION 1 -#if DEBUG_IMPLEMENTATION -# define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) -#else -# define IPRINTF(fmt, args...) do {} while (0) -#endif - /* * Exact clock frequencies vary from board to board. * These are typical. @@ -136,9 +127,8 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) { IMXEPITState *s = IMX_EPIT(opaque); uint32_t reg_value = 0; - uint32_t reg = offset >> 2; - switch (reg) { + switch (offset >> 2) { case 0: /* Control Register */ reg_value = s->cr; break; @@ -161,11 +151,12 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); break; } - DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(reg), reg_value); + DPRINTF("(%s) = 0x%08x\n", imx_epit_reg_name(offset >> 2), reg_value); return reg_value; } @@ -190,12 +181,12 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXEPITState *s = IMX_EPIT(opaque); - uint32_t reg = offset >> 2; uint64_t oldcr; - DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(reg), (uint32_t)value); + DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), + (uint32_t)value); - switch (reg) { + switch (offset >> 2) { case 0: /* CR */ oldcr = s->cr; @@ -271,7 +262,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); break; } From 054535262fce994b942039b0a7c4c484c8026c5e Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Sun, 25 Oct 2015 15:16:26 +0100 Subject: [PATCH 13/27] i.MX: Standardize i.MX GPT debug The goal is to have debug code always compiled during build. We standardize all debug output on the following format: [QOM_TYPE_NAME]reporting_function: debug message We also replace IPRINTF with qemu_log_mask(). The qemu_log_mask() output is following the same format as the above debug. Reviewed-by: Peter Crosthwaite Signed-off-by: Jean-Christophe Dubois Message-id: b7ce7e98a051479453744aded122789531d80a44.1445781957.git.jcd@tribudubois.net Signed-off-by: Peter Maydell --- hw/timer/imx_gpt.c | 56 +++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 4bac67d333..7257f4201a 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -16,11 +16,17 @@ #include "hw/misc/imx_ccm.h" #include "qemu/main-loop.h" -/* - * Define to 1 for debug messages - */ -#define DEBUG_TIMER 0 -#if DEBUG_TIMER +#ifndef DEBUG_IMX_GPT +#define DEBUG_IMX_GPT 0 +#endif + +#define DPRINTF(fmt, args...) \ + do { \ + if (DEBUG_IMX_GPT) { \ + fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \ + __func__, ##args); \ + } \ + } while (0) static char const *imx_gpt_reg_name(uint32_t reg) { @@ -50,24 +56,6 @@ static char const *imx_gpt_reg_name(uint32_t reg) } } -# define DPRINTF(fmt, args...) \ - do { printf("%s: " fmt , __func__, ##args); } while (0) -#else -# define DPRINTF(fmt, args...) do {} while (0) -#endif - -/* - * Define to 1 for messages about attempts to - * access unimplemented registers or similar. - */ -#define DEBUG_IMPLEMENTATION 1 -#if DEBUG_IMPLEMENTATION -# define IPRINTF(fmt, args...) \ - do { fprintf(stderr, "%s: " fmt, __func__, ##args); } while (0) -#else -# define IPRINTF(fmt, args...) do {} while (0) -#endif - static const VMStateDescription vmstate_imx_timer_gpt = { .name = TYPE_IMX_GPT, .version_id = 3, @@ -224,9 +212,8 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) { IMXGPTState *s = IMX_GPT(opaque); uint32_t reg_value = 0; - uint32_t reg = offset >> 2; - switch (reg) { + switch (offset >> 2) { case 0: /* Control Register */ reg_value = s->cr; break; @@ -256,12 +243,14 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) break; case 7: /* input Capture Register 1 */ - qemu_log_mask(LOG_UNIMP, "icr1 feature is not implemented\n"); + qemu_log_mask(LOG_UNIMP, "[%s]%s: icr1 feature is not implemented\n", + TYPE_IMX_GPT, __func__); reg_value = s->icr1; break; case 8: /* input Capture Register 2 */ - qemu_log_mask(LOG_UNIMP, "icr2 feature is not implemented\n"); + qemu_log_mask(LOG_UNIMP, "[%s]%s: icr2 feature is not implemented\n", + TYPE_IMX_GPT, __func__); reg_value = s->icr2; break; @@ -271,11 +260,12 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); break; } - DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(reg), reg_value); + DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value); return reg_value; } @@ -322,12 +312,11 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, { IMXGPTState *s = IMX_GPT(opaque); uint32_t oldreg; - uint32_t reg = offset >> 2; - DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(reg), + DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2), (uint32_t)value); - switch (reg) { + switch (offset >> 2) { case 0: oldreg = s->cr; s->cr = value & ~0x7c14; @@ -403,7 +392,8 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, break; default: - IPRINTF("Bad offset %x\n", reg); + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" + HWADDR_PRIx "\n", TYPE_IMX_GPT, __func__, offset); break; } } From 59e055307392fdf99b86c8cbcd33a7e261dcbdb1 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:54 +0100 Subject: [PATCH 14/27] target-arm: Add HPFAR_EL2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-2-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 + target-arm/helper.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index a2712057ab..815fef8a30 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -279,6 +279,7 @@ typedef struct CPUARMState { }; uint64_t far_el[4]; }; + uint64_t hpfar_el2; union { /* Translation result. */ struct { uint64_t _unused_par_0; diff --git a/target-arm/helper.c b/target-arm/helper.c index aba5025403..7e3558593a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3230,6 +3230,10 @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = { { .name = "MDCR_EL2", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, .access = PL2_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, + { .name = "HPFAR_EL2", .state = ARM_CP_STATE_BOTH, + .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, + .access = PL2_RW, .accessfn = access_el3_aa32ns_aa64any, + .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; @@ -3476,6 +3480,14 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { .opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 1, .access = PL2_RW, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el2), }, + { .name = "HPFAR", .state = ARM_CP_STATE_AA32, + .cp = 15, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, + .access = PL2_RW, .accessfn = access_el3_aa32ns, + .fieldoffset = offsetof(CPUARMState, cp15.hpfar_el2) }, + { .name = "HPFAR_EL2", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 4, + .access = PL2_RW, + .fieldoffset = offsetof(CPUARMState, cp15.hpfar_el2) }, REGINFO_SENTINEL }; From 5c31a10d16c595d6a59e3e7fc1808c3b1d03e02f Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:55 +0100 Subject: [PATCH 15/27] target-arm: lpae: Make t0sz and t1sz signed integers Make t0sz and t1sz signed integers to match tsz and to make it easier to implement support for AArch32 negative t0sz. t1sz is changed for consistensy. No functional change. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-3-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 7e3558593a..d07b4b7cf3 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6535,12 +6535,12 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - uint32_t t0sz = extract32(tcr->raw_tcr, 0, 6); + int32_t t0sz = extract32(tcr->raw_tcr, 0, 6); if (va_size == 64) { t0sz = MIN(t0sz, 39); t0sz = MAX(t0sz, 16); } - uint32_t t1sz = extract32(tcr->raw_tcr, 16, 6); + int32_t t1sz = extract32(tcr->raw_tcr, 16, 6); if (va_size == 64) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); From 1f4c8c18a5b6f4fad13e13b7e3828124c6c8f34d Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:56 +0100 Subject: [PATCH 16/27] target-arm: lpae: Move declaration of t0sz and t1sz Move declaration of t0sz and t1sz to the top of the function avoiding a mix of code and variable declarations. No functional change. Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-4-git-send-email-edgar.iglesias@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index d07b4b7cf3..0086febf43 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6480,6 +6480,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUFaultType fault_type = translation_fault; uint32_t level = 1; uint32_t epd = 0; + int32_t t0sz, t1sz; int32_t tsz; uint32_t tg; uint64_t ttbr; @@ -6535,12 +6536,12 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - int32_t t0sz = extract32(tcr->raw_tcr, 0, 6); + t0sz = extract32(tcr->raw_tcr, 0, 6); if (va_size == 64) { t0sz = MIN(t0sz, 39); t0sz = MAX(t0sz, 16); } - int32_t t1sz = extract32(tcr->raw_tcr, 16, 6); + t1sz = extract32(tcr->raw_tcr, 16, 6); if (va_size == 64) { t1sz = MIN(t1sz, 39); t1sz = MAX(t1sz, 16); From 4ee38098010240e0b390061fdd0151ff62d80279 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:57 +0100 Subject: [PATCH 17/27] target-arm: Add support for AArch32 S2 negative t0sz Add support for AArch32 S2 negative t0sz. In preparation for using 40bit IPAs on AArch32. Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-5-git-send-email-edgar.iglesias@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 0086febf43..d2f035f984 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6536,10 +6536,26 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * This is a Non-secure PL0/1 stage 1 translation, so controlled by * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32: */ - t0sz = extract32(tcr->raw_tcr, 0, 6); if (va_size == 64) { + /* AArch64 translation. */ + t0sz = extract32(tcr->raw_tcr, 0, 6); t0sz = MIN(t0sz, 39); t0sz = MAX(t0sz, 16); + } else if (mmu_idx != ARMMMUIdx_S2NS) { + /* AArch32 stage 1 translation. */ + t0sz = extract32(tcr->raw_tcr, 0, 3); + } else { + /* AArch32 stage 2 translation. */ + bool sext = extract32(tcr->raw_tcr, 4, 1); + bool sign = extract32(tcr->raw_tcr, 3, 1); + t0sz = sextract32(tcr->raw_tcr, 0, 4); + + /* If the sign-extend bit is not the same as t0sz[3], the result + * is unpredictable. Flag this as a guest error. */ + if (sign != sext) { + qemu_log_mask(LOG_GUEST_ERROR, + "AArch32: VTCR.S / VTCR.T0SZ[3] missmatch\n"); + } } t1sz = extract32(tcr->raw_tcr, 16, 6); if (va_size == 64) { From 4ca6a051758edf625a17dfc4ce4ab72edabac170 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:58 +0100 Subject: [PATCH 18/27] target-arm: lpae: Replace tsz with computed inputsize Remove the tsz variable and introduce inputsize. This simplifies the code a little and makes it easier to compare with the reference manuals. No functional change. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-6-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index d2f035f984..982d8306d7 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6481,7 +6481,6 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint32_t level = 1; uint32_t epd = 0; int32_t t0sz, t1sz; - int32_t tsz; uint32_t tg; uint64_t ttbr; int ttbr_select; @@ -6491,6 +6490,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint32_t attrs; int32_t granule_sz = 9; int32_t va_size = 32; + int inputsize; int32_t tbi = 0; TCR *tcr = regime_tcr(env, mmu_idx); int ap, ns, xn, pxn; @@ -6593,7 +6593,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, if (el < 2) { epd = extract32(tcr->raw_tcr, 7, 1); } - tsz = t0sz; + inputsize = va_size - t0sz; tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ @@ -6608,7 +6608,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ttbr = regime_ttbr(env, mmu_idx, 1); epd = extract32(tcr->raw_tcr, 23, 1); - tsz = t1sz; + inputsize = va_size - t1sz; tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ @@ -6620,7 +6620,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } /* Here we should have set up all the parameters for the translation: - * va_size, ttbr, epd, tsz, granule_sz, tbi + * va_size, inputsize, ttbr, epd, granule_sz, tbi */ if (epd) { @@ -6635,27 +6635,27 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * of strides (granule_sz bits at a time) needed to consume the bits * of the input address. In the pseudocode this is: * level = 4 - RoundUp((inputsize - grainsize) / stride) - * where their 'inputsize' is our 'va_size - tsz', 'grainsize' is + * where their 'inputsize' is our 'inputsize', 'grainsize' is * our 'granule_sz + 3' and 'stride' is our 'granule_sz'. * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: - * = 4 - (va_size - tsz - granule_sz - 3 + granule_sz - 1) / granule_sz - * = 4 - (va_size - tsz - 4) / granule_sz; + * = 4 - (inputsize - granule_sz - 3 + granule_sz - 1) / granule_sz + * = 4 - (inputsize - 4) / granule_sz; */ - level = 4 - (va_size - tsz - 4) / granule_sz; + level = 4 - (inputsize - 4) / granule_sz; /* Clear the vaddr bits which aren't part of the within-region address, * so that we don't have to special case things when calculating the * first descriptor address. */ - if (tsz) { - address &= (1ULL << (va_size - tsz)) - 1; + if (va_size != inputsize) { + address &= (1ULL << inputsize) - 1; } descmask = (1ULL << (granule_sz + 3)) - 1; /* Now we can extract the actual base address from the TTBR */ descaddr = extract64(ttbr, 0, 48); - descaddr &= ~((1ULL << (va_size - tsz - (granule_sz * (4 - level)))) - 1); + descaddr &= ~((1ULL << (inputsize - (granule_sz * (4 - level)))) - 1); /* Secure accesses start with the page table in secure memory and * can be downgraded to non-secure at any step. Non-secure accesses From 973a5434825c076995218868b5b3047e5de400c6 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:01:59 +0100 Subject: [PATCH 19/27] target-arm: lpae: Rename granule_sz to stride Rename granule_sz to stride to better match the reference manuals. No functional change. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-7-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 982d8306d7..2af126ff4a 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6488,7 +6488,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint32_t tableattrs; target_ulong page_size; uint32_t attrs; - int32_t granule_sz = 9; + int32_t stride = 9; int32_t va_size = 32; int inputsize; int32_t tbi = 0; @@ -6597,10 +6597,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, tg = extract32(tcr->raw_tcr, 14, 2); if (tg == 1) { /* 64KB pages */ - granule_sz = 13; + stride = 13; } if (tg == 2) { /* 16KB pages */ - granule_sz = 11; + stride = 11; } } else { /* We should only be here if TTBR1 is valid */ @@ -6612,15 +6612,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, tg = extract32(tcr->raw_tcr, 30, 2); if (tg == 3) { /* 64KB pages */ - granule_sz = 13; + stride = 13; } if (tg == 1) { /* 16KB pages */ - granule_sz = 11; + stride = 11; } } /* Here we should have set up all the parameters for the translation: - * va_size, inputsize, ttbr, epd, granule_sz, tbi + * va_size, inputsize, ttbr, epd, stride, tbi */ if (epd) { @@ -6632,16 +6632,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* The starting level depends on the virtual address size (which can be * up to 48 bits) and the translation granule size. It indicates the number - * of strides (granule_sz bits at a time) needed to consume the bits + * of strides (stride bits at a time) needed to consume the bits * of the input address. In the pseudocode this is: * level = 4 - RoundUp((inputsize - grainsize) / stride) * where their 'inputsize' is our 'inputsize', 'grainsize' is - * our 'granule_sz + 3' and 'stride' is our 'granule_sz'. + * our 'stride + 3' and 'stride' is our 'stride'. * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: - * = 4 - (inputsize - granule_sz - 3 + granule_sz - 1) / granule_sz - * = 4 - (inputsize - 4) / granule_sz; + * = 4 - (inputsize - stride - 3 + stride - 1) / stride + * = 4 - (inputsize - 4) / stride; */ - level = 4 - (inputsize - 4) / granule_sz; + level = 4 - (inputsize - 4) / stride; /* Clear the vaddr bits which aren't part of the within-region address, * so that we don't have to special case things when calculating the @@ -6651,11 +6651,11 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, address &= (1ULL << inputsize) - 1; } - descmask = (1ULL << (granule_sz + 3)) - 1; + descmask = (1ULL << (stride + 3)) - 1; /* Now we can extract the actual base address from the TTBR */ descaddr = extract64(ttbr, 0, 48); - descaddr &= ~((1ULL << (inputsize - (granule_sz * (4 - level)))) - 1); + descaddr &= ~((1ULL << (inputsize - (stride * (4 - level)))) - 1); /* Secure accesses start with the page table in secure memory and * can be downgraded to non-secure at any step. Non-secure accesses @@ -6667,7 +6667,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, uint64_t descriptor; bool nstable; - descaddr |= (address >> (granule_sz * (4 - level))) & descmask; + descaddr |= (address >> (stride * (4 - level))) & descmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); descriptor = arm_ldq_ptw(cs, descaddr, !nstable); @@ -6692,7 +6692,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, * These are basically the same thing, although the number * of bits we pull in from the vaddr varies. */ - page_size = (1ULL << ((granule_sz * (4 - level)) + 3)); + page_size = (1ULL << ((stride * (4 - level)) + 3)); descaddr |= (address & (page_size - 1)); /* Extract attributes from the descriptor and merge with table attrs */ attrs = extract64(descriptor, 2, 10) From 1853d5a9dcac910322c6cc5b2fddec45fd052d25 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:00 +0100 Subject: [PATCH 20/27] target-arm: Add computation of starting level for S2 PTW The starting level for S2 pagetable walks is computed differently from the S1 starting level. Implement the S2 variant. Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-8-git-send-email-edgar.iglesias@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 114 ++++++++++++++++++++++++++++++++++++----- target-arm/internals.h | 25 +++++++++ 2 files changed, 126 insertions(+), 13 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 2af126ff4a..8714724488 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6470,12 +6470,72 @@ typedef enum { permission_fault = 3, } MMUFaultType; +/* + * check_s2_startlevel + * @cpu: ARMCPU + * @is_aa64: True if the translation regime is in AArch64 state + * @startlevel: Suggested starting level + * @inputsize: Bitsize of IPAs + * @stride: Page-table stride (See the ARM ARM) + * + * Returns true if the suggested starting level is OK and false otherwise. + */ +static bool check_s2_startlevel(ARMCPU *cpu, bool is_aa64, int level, + int inputsize, int stride) +{ + /* Negative levels are never allowed. */ + if (level < 0) { + return false; + } + + if (is_aa64) { + unsigned int pamax = arm_pamax(cpu); + + switch (stride) { + case 13: /* 64KB Pages. */ + if (level == 0 || (level == 1 && pamax <= 42)) { + return false; + } + break; + case 11: /* 16KB Pages. */ + if (level == 0 || (level == 1 && pamax <= 40)) { + return false; + } + break; + case 9: /* 4KB Pages. */ + if (level == 0 && pamax <= 42) { + return false; + } + break; + default: + g_assert_not_reached(); + } + } else { + const int grainsize = stride + 3; + int startsizecheck; + + /* AArch32 only supports 4KB pages. Assert on that. */ + assert(stride == 9); + + if (level == 0) { + return false; + } + + startsizecheck = inputsize - ((3 - level) * stride + grainsize); + if (startsizecheck < 1 || startsizecheck > stride + 4) { + return false; + } + } + return true; +} + static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, target_ulong *page_size_ptr, uint32_t *fsr) { - CPUState *cs = CPU(arm_env_get_cpu(env)); + ARMCPU *cpu = arm_env_get_cpu(env); + CPUState *cs = CPU(cpu); /* Read an LPAE long-descriptor translation table. */ MMUFaultType fault_type = translation_fault; uint32_t level = 1; @@ -6630,18 +6690,46 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, goto do_fault; } - /* The starting level depends on the virtual address size (which can be - * up to 48 bits) and the translation granule size. It indicates the number - * of strides (stride bits at a time) needed to consume the bits - * of the input address. In the pseudocode this is: - * level = 4 - RoundUp((inputsize - grainsize) / stride) - * where their 'inputsize' is our 'inputsize', 'grainsize' is - * our 'stride + 3' and 'stride' is our 'stride'. - * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: - * = 4 - (inputsize - stride - 3 + stride - 1) / stride - * = 4 - (inputsize - 4) / stride; - */ - level = 4 - (inputsize - 4) / stride; + if (mmu_idx != ARMMMUIdx_S2NS) { + /* The starting level depends on the virtual address size (which can + * be up to 48 bits) and the translation granule size. It indicates + * the number of strides (stride bits at a time) needed to + * consume the bits of the input address. In the pseudocode this is: + * level = 4 - RoundUp((inputsize - grainsize) / stride) + * where their 'inputsize' is our 'inputsize', 'grainsize' is + * our 'stride + 3' and 'stride' is our 'stride'. + * Applying the usual "rounded up m/n is (m+n-1)/n" and simplifying: + * = 4 - (inputsize - stride - 3 + stride - 1) / stride + * = 4 - (inputsize - 4) / stride; + */ + level = 4 - (inputsize - 4) / stride; + } else { + /* For stage 2 translations the starting level is specified by the + * VTCR_EL2.SL0 field (whose interpretation depends on the page size) + */ + int startlevel = extract32(tcr->raw_tcr, 6, 2); + bool ok; + + if (va_size == 32 || stride == 9) { + /* AArch32 or 4KB pages */ + level = 2 - startlevel; + } else { + /* 16KB or 64KB pages */ + level = 3 - startlevel; + } + + /* Check that the starting level is valid. */ + ok = check_s2_startlevel(cpu, va_size == 64, level, + inputsize, stride); + if (!ok) { + /* AArch64 reports these as level 0 faults. + * AArch32 reports these as level 1 faults. + */ + level = va_size == 64 ? 0 : 1; + fault_type = translation_fault; + goto do_fault; + } + } /* Clear the vaddr bits which aren't part of the within-region address, * so that we don't have to special case things when calculating the diff --git a/target-arm/internals.h b/target-arm/internals.h index 36a56aadb0..8bd37eba65 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -152,6 +152,31 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm) aarch64_restore_sp(env, cur_el); } +/* + * arm_pamax + * @cpu: ARMCPU + * + * Returns the implementation defined bit-width of physical addresses. + * The ARMv8 reference manuals refer to this as PAMax(). + */ +static inline unsigned int arm_pamax(ARMCPU *cpu) +{ + static const unsigned int pamax_map[] = { + [0] = 32, + [1] = 36, + [2] = 40, + [3] = 42, + [4] = 44, + [5] = 48, + }; + unsigned int parange = extract32(cpu->id_aa64mmfr0, 0, 4); + + /* id_aa64mmfr0 is a read-only register so values outside of the + * supported mappings can be considered an implementation error. */ + assert(parange < ARRAY_SIZE(pamax_map)); + return pamax_map[parange]; +} + /* Return true if extended addresses are enabled. * This is always the case if our translation regime is 64 bit, * but depends on TTBCR.EAE for 32 bit. From 6ab1a5ee1c9d328cacf78805439ed4d3d132decd Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:01 +0100 Subject: [PATCH 21/27] target-arm: Add support for S2 page-table protection bits Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-9-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 8714724488..b58440b73b 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6079,6 +6079,28 @@ simple_ap_to_rw_prot(CPUARMState *env, ARMMMUIdx mmu_idx, int ap) return simple_ap_to_rw_prot_is_user(ap, regime_is_user(env, mmu_idx)); } +/* Translate S2 section/page access permissions to protection flags + * + * @env: CPUARMState + * @s2ap: The 2-bit stage2 access permissions (S2AP) + * @xn: XN (execute-never) bit + */ +static int get_S2prot(CPUARMState *env, int s2ap, int xn) +{ + int prot = 0; + + if (s2ap & 1) { + prot |= PAGE_READ; + } + if (s2ap & 2) { + prot |= PAGE_WRITE; + } + if (!xn) { + prot |= PAGE_EXEC; + } + return prot; +} + /* Translate section/page access permissions to protection flags * * @env: CPUARMState @@ -6782,9 +6804,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, */ page_size = (1ULL << ((stride * (4 - level)) + 3)); descaddr |= (address & (page_size - 1)); - /* Extract attributes from the descriptor and merge with table attrs */ + /* Extract attributes from the descriptor */ attrs = extract64(descriptor, 2, 10) | (extract64(descriptor, 52, 12) << 10); + + if (mmu_idx == ARMMMUIdx_S2NS) { + /* Stage 2 table descriptors do not include any attribute fields */ + break; + } + /* Merge in attributes from table descriptors */ attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */ attrs |= extract32(tableattrs, 3, 1) << 5; /* APTable[1] => AP[2] */ /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 @@ -6806,11 +6834,16 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, } ap = extract32(attrs, 4, 2); - ns = extract32(attrs, 3, 1); xn = extract32(attrs, 12, 1); - pxn = extract32(attrs, 11, 1); - *prot = get_S1prot(env, mmu_idx, va_size == 64, ap, ns, xn, pxn); + if (mmu_idx == ARMMMUIdx_S2NS) { + ns = true; + *prot = get_S2prot(env, ap, xn); + } else { + ns = extract32(attrs, 3, 1); + pxn = extract32(attrs, 11, 1); + *prot = get_S1prot(env, mmu_idx, va_size == 64, ap, ns, xn, pxn); + } fault_type = permission_fault; if (!(*prot & (1 << access_type))) { From af51f566ec7106d5e834476e78681a7b354f3c7c Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:02 +0100 Subject: [PATCH 22/27] target-arm: Avoid inline for get_phys_addr Avoid inline for get_phys_addr() to prepare for future recursive use. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-10-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index b58440b73b..4f6098b235 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -15,10 +15,10 @@ #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ #ifndef CONFIG_USER_ONLY -static inline bool get_phys_addr(CPUARMState *env, target_ulong address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr); +static bool get_phys_addr(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, uint32_t *fsr); /* Definitions for the PMCCNTR and PMCR registers */ #define PMCRD 0x8 @@ -7126,10 +7126,10 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, * @page_size: set to the size of the page containing phys_ptr * @fsr: set to the DFSR/IFSR value on failure */ -static inline bool get_phys_addr(CPUARMState *env, target_ulong address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr) +static bool get_phys_addr(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, uint32_t *fsr) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { /* TODO: when we support EL2 we should here call ourselves recursively From e14b5a23d8c83304559f31397f95d22ada60a19a Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:03 +0100 Subject: [PATCH 23/27] target-arm: Add ARMMMUFaultInfo Introduce ARMMMUFaultInfo to propagate MMU Fault information across the MMU translation code path. This is in preparation for adding Stage-2 translation. No functional changes. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-11-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 32 ++++++++++++++++++++------------ target-arm/internals.h | 15 ++++++++++++++- target-arm/op_helper.c | 3 ++- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 4f6098b235..3142761157 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -18,7 +18,8 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr); + target_ulong *page_size, uint32_t *fsr, + ARMMMUFaultInfo *fi); /* Definitions for the PMCCNTR and PMCR registers */ #define PMCRD 0x8 @@ -1778,9 +1779,10 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, bool ret; uint64_t par64; MemTxAttrs attrs = {}; + ARMMMUFaultInfo fi = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, - &phys_addr, &attrs, &prot, &page_size, &fsr); + &phys_addr, &attrs, &prot, &page_size, &fsr, &fi); if (extended_addresses_enabled(env)) { /* fsr is a DFSR/IFSR value for the long descriptor * translation table format, but with WnR always clear. @@ -6231,7 +6233,8 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure) static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, - target_ulong *page_size, uint32_t *fsr) + target_ulong *page_size, uint32_t *fsr, + ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); int code; @@ -6344,7 +6347,8 @@ do_fault: static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr) + target_ulong *page_size, uint32_t *fsr, + ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); int code; @@ -6554,7 +6558,8 @@ static bool check_s2_startlevel(ARMCPU *cpu, bool is_aa64, int level, static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, uint32_t *fsr) + target_ulong *page_size_ptr, uint32_t *fsr, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = arm_env_get_cpu(env); CPUState *cs = CPU(cpu); @@ -7129,7 +7134,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, static bool get_phys_addr(CPUARMState *env, target_ulong address, int access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr) + target_ulong *page_size, uint32_t *fsr, + ARMMMUFaultInfo *fi) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { /* TODO: when we support EL2 we should here call ourselves recursively @@ -7188,13 +7194,13 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, if (regime_using_lpae_format(env, mmu_idx)) { return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr); + attrs, prot, page_size, fsr, fi); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr); + attrs, prot, page_size, fsr, fi); } else { return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, - prot, page_size, fsr); + prot, page_size, fsr, fi); } } @@ -7203,7 +7209,8 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, * fsr with ARM DFSR/IFSR fault register format value on failure. */ bool arm_tlb_fill(CPUState *cs, vaddr address, - int access_type, int mmu_idx, uint32_t *fsr) + int access_type, int mmu_idx, uint32_t *fsr, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -7214,7 +7221,7 @@ bool arm_tlb_fill(CPUState *cs, vaddr address, MemTxAttrs attrs = {}; ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr, - &attrs, &prot, &page_size, fsr); + &attrs, &prot, &page_size, fsr, fi); if (!ret) { /* Map a single [sub]page. */ phys_addr &= TARGET_PAGE_MASK; @@ -7237,9 +7244,10 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) bool ret; uint32_t fsr; MemTxAttrs attrs = {}; + ARMMMUFaultInfo fi = {}; ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env, false), &phys_addr, - &attrs, &prot, &page_size, &fsr); + &attrs, &prot, &page_size, &fsr, &fi); if (ret) { return -1; diff --git a/target-arm/internals.h b/target-arm/internals.h index 8bd37eba65..412827bcbf 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -414,8 +414,21 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type); void arm_handle_psci_call(ARMCPU *cpu); #endif +/** + * ARMMMUFaultInfo: Information describing an ARM MMU Fault + * @s2addr: Address that caused a fault at stage 2 + * @stage2: True if we faulted at stage 2 + * @s1ptw: True if we faulted at stage 2 while doing a stage 1 page-table walk + */ +typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; +struct ARMMMUFaultInfo { + target_ulong s2addr; + bool stage2; + bool s1ptw; +}; + /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx, - uint32_t *fsr); + uint32_t *fsr, ARMMMUFaultInfo *fi); #endif diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 7929c71b43..86a6d038c7 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -83,8 +83,9 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, { bool ret; uint32_t fsr = 0; + ARMMMUFaultInfo fi = {}; - ret = arm_tlb_fill(cs, addr, is_write, mmu_idx, &fsr); + ret = arm_tlb_fill(cs, addr, is_write, mmu_idx, &fsr, &fi); if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; From 37785977627295162bff58b1f8777d94e20f4c5b Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:04 +0100 Subject: [PATCH 24/27] target-arm: Add S2 translation to 64bit S1 PTWs Add support for applying S2 translation to 64bit S1 page-table walks. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-12-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 50 ++++++++++++++++++++++++++++++++++++++++-- target-arm/op_helper.c | 4 ++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 3142761157..bd395169ff 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -21,6 +21,12 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, target_ulong *page_size, uint32_t *fsr, ARMMMUFaultInfo *fi); +static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, uint32_t *fsr, + ARMMMUFaultInfo *fi); + /* Definitions for the PMCCNTR and PMCR registers */ #define PMCRD 0x8 #define PMCRC 0x4 @@ -6207,6 +6213,32 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, return true; } +/* Translate a S1 pagetable walk through S2 if needed. */ +static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, + hwaddr addr, MemTxAttrs txattrs, + uint32_t *fsr, + ARMMMUFaultInfo *fi) +{ + if ((mmu_idx == ARMMMUIdx_S1NSE0 || mmu_idx == ARMMMUIdx_S1NSE1) && + !regime_translation_disabled(env, ARMMMUIdx_S2NS)) { + target_ulong s2size; + hwaddr s2pa; + int s2prot; + int ret; + + ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, + &txattrs, &s2prot, &s2size, fsr, fi); + if (ret) { + fi->s2addr = addr; + fi->stage2 = true; + fi->s1ptw = true; + return ~0; + } + addr = s2pa; + } + return addr; +} + /* All loads done in the course of a page table walk go through here. * TODO: rather than ignoring errors from physical memory reads (which * are external aborts in ARM terminology) we should propagate this @@ -6222,11 +6254,19 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure) return address_space_ldl(cs->as, addr, attrs, NULL); } -static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure) +static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, uint32_t *fsr, + ARMMMUFaultInfo *fi) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; attrs.secure = is_secure; + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + if (fi->s1ptw) { + return 0; + } return address_space_ldq(cs->as, addr, attrs, NULL); } @@ -6785,7 +6825,11 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, descaddr |= (address >> (stride * (4 - level))) & descmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable); + descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fsr, fi); + if (fi->s1ptw) { + goto do_fault; + } + if (!(descriptor & 1) || (!(descriptor & 2) && (level == 3))) { /* Invalid, or the Reserved level 3 encoding */ @@ -6869,6 +6913,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, do_fault: /* Long-descriptor format IFSR/DFSR value */ *fsr = (1 << 9) | (fault_type << 2) | level; + /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ + fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_S2NS); return true; } diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 86a6d038c7..36dac27a90 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -104,10 +104,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, * information; this is always true for exceptions reported to EL1. */ if (is_write == 2) { - syn = syn_insn_abort(same_el, 0, 0, syn); + syn = syn_insn_abort(same_el, 0, fi.s1ptw, syn); exc = EXCP_PREFETCH_ABORT; } else { - syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn); + syn = syn_data_abort(same_el, 0, 0, fi.s1ptw, is_write == 1, syn); if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) { fsr |= (1 << 11); } From a614e69854a2e601716ee44dfe15c09b8b88f620 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:05 +0100 Subject: [PATCH 25/27] target-arm: Add S2 translation to 32bit S1 PTWs Add support for applying S2 translation to 32bit S1 page-table walks. Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-13-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index bd395169ff..eb9a00d14e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -6246,11 +6246,19 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, * was being done for a CPU load/store or an address translation instruction * (but not if it was for a debug access). */ -static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure) +static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, + ARMMMUIdx mmu_idx, uint32_t *fsr, + ARMMMUFaultInfo *fi) { + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; MemTxAttrs attrs = {}; attrs.secure = is_secure; + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + if (fi->s1ptw) { + return 0; + } return address_space_ldl(cs->as, addr, attrs, NULL); } @@ -6294,7 +6302,8 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, code = 5; goto do_fault; } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx)); + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fsr, fi); type = (desc & 3); domain = (desc >> 5) & 0x0f; if (regime_el(env, mmu_idx) == 1) { @@ -6330,7 +6339,8 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Fine pagetable. */ table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx)); + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fsr, fi); switch (desc & 3) { case 0: /* Page translation fault. */ code = 7; @@ -6411,7 +6421,8 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, code = 5; goto do_fault; } - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx)); + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fsr, fi); type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { /* Section translation fault, or attempt to use the encoding @@ -6462,7 +6473,8 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ns = extract32(desc, 3, 1); /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); - desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx)); + desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), + mmu_idx, fsr, fi); ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ From d759a457a144844bff259aafda093b24e92c116d Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:06 +0100 Subject: [PATCH 26/27] target-arm: Route S2 MMU faults to EL2 Reviewed-by: Peter Maydell Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-14-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/op_helper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 36dac27a90..333078a169 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -90,13 +90,19 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; uint32_t syn, exc; - bool same_el = (arm_current_el(env) != 0); + unsigned int target_el; + bool same_el; if (retaddr) { /* now we have a real cpu fault */ cpu_restore_state(cs, retaddr); } + target_el = exception_target_el(env); + if (fi.stage2) { + target_el = 2; + } + same_el = arm_current_el(env) == target_el; /* AArch64 syndrome does not have an LPAE bit */ syn = fsr & ~(1 << 9); @@ -116,7 +122,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, env->exception.vaddress = addr; env->exception.fsr = fsr; - raise_exception(env, exc, syn, exception_target_el(env)); + raise_exception(env, exc, syn, target_el); } } #endif From 9b539263faa5c1b7fce2551092b5c7b6eea92081 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Mon, 26 Oct 2015 14:02:07 +0100 Subject: [PATCH 27/27] target-arm: Add support for S1 + S2 MMU translations Signed-off-by: Edgar E. Iglesias Message-id: 1445864527-14520-15-git-send-email-edgar.iglesias@gmail.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 38 +++++++++++++++++++++++++++++++------- target-arm/op_helper.c | 1 + 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index eb9a00d14e..1966f9c045 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -7196,14 +7196,38 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, ARMMMUFaultInfo *fi) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { - /* TODO: when we support EL2 we should here call ourselves recursively - * to do the stage 1 and then stage 2 translations. The arm_ld*_ptw - * functions will also need changing to perform ARMMMUIdx_S2NS loads - * rather than direct physical memory loads when appropriate. - * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. + /* Call ourselves recursively to do the stage 1 and then stage 2 + * translations. */ - assert(!arm_feature(env, ARM_FEATURE_EL2)); - mmu_idx += ARMMMUIdx_S1NSE0; + if (arm_feature(env, ARM_FEATURE_EL2)) { + hwaddr ipa; + int s2_prot; + int ret; + + ret = get_phys_addr(env, address, access_type, + mmu_idx + ARMMMUIdx_S1NSE0, &ipa, attrs, + prot, page_size, fsr, fi); + + /* If S1 fails or S2 is disabled, return early. */ + if (ret || regime_translation_disabled(env, ARMMMUIdx_S2NS)) { + *phys_ptr = ipa; + return ret; + } + + /* S1 is done. Now do S2 translation. */ + ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_S2NS, + phys_ptr, attrs, &s2_prot, + page_size, fsr, fi); + fi->s2addr = ipa; + /* Combine the S1 and S2 perms. */ + *prot &= s2_prot; + return ret; + } else { + /* + * For non-EL2 CPUs a stage1+stage2 translation is just stage 1. + */ + mmu_idx += ARMMMUIdx_S1NSE0; + } } /* The page table entries may downgrade secure to non-secure, but diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 333078a169..a4c4ebf9cd 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -101,6 +101,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, target_el = exception_target_el(env); if (fi.stage2) { target_el = 2; + env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4; } same_el = arm_current_el(env) == target_el; /* AArch64 syndrome does not have an LPAE bit */