diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 5455dbf326..45e75081e8 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -285,9 +285,9 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode) spitz_keyboard_sense_update(s); } -#define MOD_SHIFT (1 << 7) -#define MOD_CTRL (1 << 8) -#define MOD_FN (1 << 9) +#define SPITZ_MOD_SHIFT (1 << 7) +#define SPITZ_MOD_CTRL (1 << 8) +#define SPITZ_MOD_FN (1 << 9) #define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c @@ -324,21 +324,26 @@ static void spitz_keyboard_handler(void *opaque, int keycode) } code = s->pre_map[mapcode = ((s->modifiers & 3) ? - (keycode | MOD_SHIFT) : - (keycode & ~MOD_SHIFT))]; + (keycode | SPITZ_MOD_SHIFT) : + (keycode & ~SPITZ_MOD_SHIFT))]; if (code != mapcode) { #if 0 - if ((code & MOD_SHIFT) && !(s->modifiers & 1)) + if ((code & SPITZ_MOD_SHIFT) && !(s->modifiers & 1)) { QUEUE_KEY(0x2a | (keycode & 0x80)); - if ((code & MOD_CTRL ) && !(s->modifiers & 4)) + } + if ((code & SPITZ_MOD_CTRL) && !(s->modifiers & 4)) { QUEUE_KEY(0x1d | (keycode & 0x80)); - if ((code & MOD_FN ) && !(s->modifiers & 8)) + } + if ((code & SPITZ_MOD_FN) && !(s->modifiers & 8)) { QUEUE_KEY(0x38 | (keycode & 0x80)); - if ((code & MOD_FN ) && (s->modifiers & 1)) + } + if ((code & SPITZ_MOD_FN) && (s->modifiers & 1)) { QUEUE_KEY(0x2a | (~keycode & 0x80)); - if ((code & MOD_FN ) && (s->modifiers & 2)) + } + if ((code & SPITZ_MOD_FN) && (s->modifiers & 2)) { QUEUE_KEY(0x36 | (~keycode & 0x80)); + } #else if (keycode & 0x80) { if ((s->imodifiers & 1 ) && !(s->modifiers & 1)) @@ -353,24 +358,27 @@ static void spitz_keyboard_handler(void *opaque, int keycode) QUEUE_KEY(0x36); s->imodifiers = 0; } else { - if ((code & MOD_SHIFT) && !((s->modifiers | s->imodifiers) & 1)) { + if ((code & SPITZ_MOD_SHIFT) && + !((s->modifiers | s->imodifiers) & 1)) { QUEUE_KEY(0x2a); s->imodifiers |= 1; } - if ((code & MOD_CTRL ) && !((s->modifiers | s->imodifiers) & 4)) { + if ((code & SPITZ_MOD_CTRL) && + !((s->modifiers | s->imodifiers) & 4)) { QUEUE_KEY(0x1d); s->imodifiers |= 4; } - if ((code & MOD_FN ) && !((s->modifiers | s->imodifiers) & 8)) { + if ((code & SPITZ_MOD_FN) && + !((s->modifiers | s->imodifiers) & 8)) { QUEUE_KEY(0x38); s->imodifiers |= 8; } - if ((code & MOD_FN ) && (s->modifiers & 1) && + if ((code & SPITZ_MOD_FN) && (s->modifiers & 1) && !(s->imodifiers & 0x10)) { QUEUE_KEY(0x2a | 0x80); s->imodifiers |= 0x10; } - if ((code & MOD_FN ) && (s->modifiers & 2) && + if ((code & SPITZ_MOD_FN) && (s->modifiers & 2) && !(s->imodifiers & 0x20)) { QUEUE_KEY(0x36 | 0x80); s->imodifiers |= 0x20; @@ -402,38 +410,38 @@ static void spitz_keyboard_pre_map(SpitzKeyboardState *s) int i; for (i = 0; i < 0x100; i ++) s->pre_map[i] = i; - s->pre_map[0x02 | MOD_SHIFT ] = 0x02 | MOD_SHIFT; /* exclam */ - s->pre_map[0x28 | MOD_SHIFT ] = 0x03 | MOD_SHIFT; /* quotedbl */ - s->pre_map[0x04 | MOD_SHIFT ] = 0x04 | MOD_SHIFT; /* numbersign */ - s->pre_map[0x05 | MOD_SHIFT ] = 0x05 | MOD_SHIFT; /* dollar */ - s->pre_map[0x06 | MOD_SHIFT ] = 0x06 | MOD_SHIFT; /* percent */ - s->pre_map[0x08 | MOD_SHIFT ] = 0x07 | MOD_SHIFT; /* ampersand */ - s->pre_map[0x28 ] = 0x08 | MOD_SHIFT; /* apostrophe */ - s->pre_map[0x0a | MOD_SHIFT ] = 0x09 | MOD_SHIFT; /* parenleft */ - s->pre_map[0x0b | MOD_SHIFT ] = 0x0a | MOD_SHIFT; /* parenright */ - s->pre_map[0x29 | MOD_SHIFT ] = 0x0b | MOD_SHIFT; /* asciitilde */ - s->pre_map[0x03 | MOD_SHIFT ] = 0x0c | MOD_SHIFT; /* at */ - s->pre_map[0xd3 ] = 0x0e | MOD_FN; /* Delete */ - s->pre_map[0x3a ] = 0x0f | MOD_FN; /* Caps_Lock */ - s->pre_map[0x07 | MOD_SHIFT ] = 0x11 | MOD_FN; /* asciicircum */ - s->pre_map[0x0d ] = 0x12 | MOD_FN; /* equal */ - s->pre_map[0x0d | MOD_SHIFT ] = 0x13 | MOD_FN; /* plus */ - s->pre_map[0x1a ] = 0x14 | MOD_FN; /* bracketleft */ - s->pre_map[0x1b ] = 0x15 | MOD_FN; /* bracketright */ - s->pre_map[0x1a | MOD_SHIFT ] = 0x16 | MOD_FN; /* braceleft */ - s->pre_map[0x1b | MOD_SHIFT ] = 0x17 | MOD_FN; /* braceright */ - s->pre_map[0x27 ] = 0x22 | MOD_FN; /* semicolon */ - s->pre_map[0x27 | MOD_SHIFT ] = 0x23 | MOD_FN; /* colon */ - s->pre_map[0x09 | MOD_SHIFT ] = 0x24 | MOD_FN; /* asterisk */ - s->pre_map[0x2b ] = 0x25 | MOD_FN; /* backslash */ - s->pre_map[0x2b | MOD_SHIFT ] = 0x26 | MOD_FN; /* bar */ - s->pre_map[0x0c | MOD_SHIFT ] = 0x30 | MOD_FN; /* underscore */ - s->pre_map[0x33 | MOD_SHIFT ] = 0x33 | MOD_FN; /* less */ - s->pre_map[0x35 ] = 0x33 | MOD_SHIFT; /* slash */ - s->pre_map[0x34 | MOD_SHIFT ] = 0x34 | MOD_FN; /* greater */ - s->pre_map[0x35 | MOD_SHIFT ] = 0x34 | MOD_SHIFT; /* question */ - s->pre_map[0x49 ] = 0x48 | MOD_FN; /* Page_Up */ - s->pre_map[0x51 ] = 0x50 | MOD_FN; /* Page_Down */ + s->pre_map[0x02 | SPITZ_MOD_SHIFT] = 0x02 | SPITZ_MOD_SHIFT; /* exclam */ + s->pre_map[0x28 | SPITZ_MOD_SHIFT] = 0x03 | SPITZ_MOD_SHIFT; /* quotedbl */ + s->pre_map[0x04 | SPITZ_MOD_SHIFT] = 0x04 | SPITZ_MOD_SHIFT; /* # */ + s->pre_map[0x05 | SPITZ_MOD_SHIFT] = 0x05 | SPITZ_MOD_SHIFT; /* dollar */ + s->pre_map[0x06 | SPITZ_MOD_SHIFT] = 0x06 | SPITZ_MOD_SHIFT; /* percent */ + s->pre_map[0x08 | SPITZ_MOD_SHIFT] = 0x07 | SPITZ_MOD_SHIFT; /* ampersand */ + s->pre_map[0x28] = 0x08 | SPITZ_MOD_SHIFT; /* ' */ + s->pre_map[0x0a | SPITZ_MOD_SHIFT] = 0x09 | SPITZ_MOD_SHIFT; /* ( */ + s->pre_map[0x0b | SPITZ_MOD_SHIFT] = 0x0a | SPITZ_MOD_SHIFT; /* ) */ + s->pre_map[0x29 | SPITZ_MOD_SHIFT] = 0x0b | SPITZ_MOD_SHIFT; /* tilde */ + s->pre_map[0x03 | SPITZ_MOD_SHIFT] = 0x0c | SPITZ_MOD_SHIFT; /* at */ + s->pre_map[0xd3] = 0x0e | SPITZ_MOD_FN; /* Delete */ + s->pre_map[0x3a] = 0x0f | SPITZ_MOD_FN; /* Caps_Lock */ + s->pre_map[0x07 | SPITZ_MOD_SHIFT] = 0x11 | SPITZ_MOD_FN; /* ^ */ + s->pre_map[0x0d] = 0x12 | SPITZ_MOD_FN; /* equal */ + s->pre_map[0x0d | SPITZ_MOD_SHIFT] = 0x13 | SPITZ_MOD_FN; /* plus */ + s->pre_map[0x1a] = 0x14 | SPITZ_MOD_FN; /* [ */ + s->pre_map[0x1b] = 0x15 | SPITZ_MOD_FN; /* ] */ + s->pre_map[0x1a | SPITZ_MOD_SHIFT] = 0x16 | SPITZ_MOD_FN; /* { */ + s->pre_map[0x1b | SPITZ_MOD_SHIFT] = 0x17 | SPITZ_MOD_FN; /* } */ + s->pre_map[0x27] = 0x22 | SPITZ_MOD_FN; /* semicolon */ + s->pre_map[0x27 | SPITZ_MOD_SHIFT] = 0x23 | SPITZ_MOD_FN; /* colon */ + s->pre_map[0x09 | SPITZ_MOD_SHIFT] = 0x24 | SPITZ_MOD_FN; /* asterisk */ + s->pre_map[0x2b] = 0x25 | SPITZ_MOD_FN; /* backslash */ + s->pre_map[0x2b | SPITZ_MOD_SHIFT] = 0x26 | SPITZ_MOD_FN; /* bar */ + s->pre_map[0x0c | SPITZ_MOD_SHIFT] = 0x30 | SPITZ_MOD_FN; /* _ */ + s->pre_map[0x33 | SPITZ_MOD_SHIFT] = 0x33 | SPITZ_MOD_FN; /* less */ + s->pre_map[0x35] = 0x33 | SPITZ_MOD_SHIFT; /* slash */ + s->pre_map[0x34 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_FN; /* greater */ + s->pre_map[0x35 | SPITZ_MOD_SHIFT] = 0x34 | SPITZ_MOD_SHIFT; /* question */ + s->pre_map[0x49] = 0x48 | SPITZ_MOD_FN; /* Page_Up */ + s->pre_map[0x51] = 0x50 | SPITZ_MOD_FN; /* Page_Down */ s->modifiers = 0; s->imodifiers = 0; @@ -441,9 +449,9 @@ static void spitz_keyboard_pre_map(SpitzKeyboardState *s) s->fifolen = 0; } -#undef MOD_SHIFT -#undef MOD_CTRL -#undef MOD_FN +#undef SPITZ_MOD_SHIFT +#undef SPITZ_MOD_CTRL +#undef SPITZ_MOD_FN static int spitz_keyboard_post_load(void *opaque, int version_id) { diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index f311595d67..3d83e6c98d 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -533,7 +533,15 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard, * If a bios file was provided, attempt to map it into memory */ if (bios_name) { - const char *fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + const char *fn; + + if (drive_get(IF_PFLASH, 0, 0)) { + error_report("The contents of the first flash device may be " + "specified with -bios or with -drive if=pflash... " + "but you cannot use both options at once"); + exit(1); + } + fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); if (!fn || load_image_targphys(fn, map[VE_NORFLASH0], VEXPRESS_FLASH_SIZE) < 0) { error_report("Could not load ROM image '%s'", bios_name); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 3b55a4bf7d..72fe030e93 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -180,10 +180,23 @@ static void create_fdt(VirtBoardInfo *vbi) "clk24mhz"); qemu_fdt_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle); +} + +static void fdt_add_psci_node(const VirtBoardInfo *vbi) +{ + void *fdt = vbi->fdt; + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); + /* No PSCI for TCG yet */ if (kvm_enabled()) { qemu_fdt_add_subnode(fdt, "/psci"); - qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + if (armcpu->psci_version == 2) { + const char comp[] = "arm,psci-0.2\0arm,psci"; + qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); + } else { + qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + } + qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc"); qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", PSCI_FN_CPU_SUSPEND); @@ -446,6 +459,7 @@ static void machvirt_init(MachineState *machine) object_property_set_bool(cpuobj, true, "realized", NULL); } fdt_add_cpu_nodes(vbi); + fdt_add_psci_node(vbi); memory_region_init_ram(ram, NULL, "mach-virt.ram", machine->ram_size); vmstate_register_ram_global(ram); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 0c95d53dca..f9507b4e5a 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -748,9 +748,18 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pflash_t *pfl = CFI_PFLASH01(dev); uint64_t total_len; int ret; + uint64_t blocks_per_device, device_len; + int num_devices; total_len = pfl->sector_len * pfl->nb_blocs; + /* These are only used to expose the parameters of each device + * in the cfi_table[]. + */ + num_devices = pfl->device_width ? (pfl->bank_width / pfl->device_width) : 1; + blocks_per_device = pfl->nb_blocs / num_devices; + device_len = pfl->sector_len * blocks_per_device; + /* XXX: to be fixed */ #if 0 if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && @@ -838,7 +847,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) /* Max timeout for chip erase */ pfl->cfi_table[0x26] = 0x00; /* Device size */ - pfl->cfi_table[0x27] = ctz32(total_len); // + 1; + pfl->cfi_table[0x27] = ctz32(device_len); /* + 1; */ /* Flash device interface (8 & 16 bits) */ pfl->cfi_table[0x28] = 0x02; pfl->cfi_table[0x29] = 0x00; @@ -854,8 +863,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) /* Number of erase block regions (uniform) */ pfl->cfi_table[0x2C] = 0x01; /* Erase block region 1 */ - pfl->cfi_table[0x2D] = pfl->nb_blocs - 1; - pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8; + pfl->cfi_table[0x2D] = blocks_per_device - 1; + pfl->cfi_table[0x2E] = (blocks_per_device - 1) >> 8; pfl->cfi_table[0x2F] = pfl->sector_len >> 8; pfl->cfi_table[0x30] = pfl->sector_len >> 16; @@ -882,6 +891,11 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) static Property pflash_cfi01_properties[] = { DEFINE_PROP_DRIVE("drive", struct pflash_t, bs), + /* num-blocks is the number of blocks actually visible to the guest, + * ie the total size of the device divided by the sector length. + * If we're emulating flash devices wired in parallel the actual + * number of blocks per indvidual device will differ. + */ DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0), DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0), /* width here is the overall width of this QEMU device in bytes. diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 75d9c6e41e..1a7af450a7 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -211,7 +211,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset) cpu = ARM_CPU(current_cpu); return cpu->env.v7m.vecbase; case 0xd0c: /* Application Interrupt/Reset Control. */ - return 0xfa05000; + return 0xfa050000; case 0xd10: /* System Control. */ /* TODO: Implement SLEEPONEXIT. */ return 0; @@ -346,6 +346,9 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) if (value & 5) { qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n"); } + if (value & 0x700) { + qemu_log_mask(LOG_UNIMP, "PRIGROUP unimplemented\n"); + } } break; case 0xd10: /* System Control. */ diff --git a/kvm-all.c b/kvm-all.c index 4e19eff0ef..ef9f0f2213 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1751,6 +1751,22 @@ int kvm_cpu_exec(CPUState *cpu) case KVM_EXIT_INTERNAL_ERROR: ret = kvm_handle_internal_error(cpu, run); break; + case KVM_EXIT_SYSTEM_EVENT: + switch (run->system_event.type) { + case KVM_SYSTEM_EVENT_SHUTDOWN: + qemu_system_shutdown_request(); + ret = EXCP_INTERRUPT; + break; + case KVM_SYSTEM_EVENT_RESET: + qemu_system_reset_request(); + ret = EXCP_INTERRUPT; + break; + default: + DPRINTF("kvm_arch_handle_exit\n"); + ret = kvm_arch_handle_exit(cpu, run); + break; + } + break; default: DPRINTF("kvm_arch_handle_exit\n"); ret = kvm_arch_handle_exit(cpu, run); diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index edc7f262fc..eaee9447ee 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -94,6 +94,12 @@ typedef struct ARMCPU { /* 'compatible' string for this CPU for Linux device trees */ const char *dtb_compatible; + /* PSCI version for this CPU + * Bits[31:16] = Major Version + * Bits[15:0] = Minor Version + */ + uint32_t psci_version; + /* Should CPU start in PSCI powered-off state? */ bool start_powered_off; @@ -102,6 +108,9 @@ typedef struct ARMCPU { */ uint32_t kvm_target; + /* KVM init features for this CPU */ + uint32_t kvm_init_features[7]; + /* The instance init functions for implementation-specific subclasses * set these fields to specify the implementation-dependent values of * various constant registers and reset values of non-constant diff --git a/target-arm/cpu.c b/target-arm/cpu.c index b8778350f7..05e52e0e83 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -260,6 +260,7 @@ static void arm_cpu_initfn(Object *obj) * picky DTB consumer will also provide a helpful error message. */ cpu->dtb_compatible = "qemu,unknown"; + cpu->psci_version = 1; /* By default assume PSCI v0.1 */ cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE; if (tcg_enabled() && !inited) { diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 79e7f82515..369d4727ae 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -430,6 +430,22 @@ int arm_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, /* Execution state bits. MRS read as zero, MSR writes ignored. */ #define CPSR_EXEC (CPSR_T | CPSR_IT | CPSR_J) +#define TTBCR_N (7U << 0) /* TTBCR.EAE==0 */ +#define TTBCR_T0SZ (7U << 0) /* TTBCR.EAE==1 */ +#define TTBCR_PD0 (1U << 4) +#define TTBCR_PD1 (1U << 5) +#define TTBCR_EPD0 (1U << 7) +#define TTBCR_IRGN0 (3U << 8) +#define TTBCR_ORGN0 (3U << 10) +#define TTBCR_SH0 (3U << 12) +#define TTBCR_T1SZ (3U << 16) +#define TTBCR_A1 (1U << 22) +#define TTBCR_EPD1 (1U << 23) +#define TTBCR_IRGN1 (3U << 24) +#define TTBCR_ORGN1 (3U << 26) +#define TTBCR_SH1 (1U << 28) +#define TTBCR_EAE (1U << 31) + /* Bit definitions for ARMv8 SPSR (PSTATE) format. * Only these are valid when in AArch64 mode; in * AArch32 mode SPSRs are basically CPSR-format. diff --git a/target-arm/helper.c b/target-arm/helper.c index 050c40981b..ed4d2bb419 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -312,7 +312,7 @@ static inline bool extended_addresses_enabled(CPUARMState *env) { return arm_el_is_aa64(env, 1) || ((arm_feature(env, ARM_FEATURE_LPAE) - && (env->cp15.c2_control & (1U << 31)))); + && (env->cp15.c2_control & TTBCR_EAE))); } static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) @@ -1413,11 +1413,22 @@ static void vmsa_ttbcr_raw_write(CPUARMState *env, const ARMCPRegInfo *ri, { int maskshift = extract32(value, 0, 3); - if (arm_feature(env, ARM_FEATURE_LPAE) && (value & (1 << 31))) { - value &= ~((7 << 19) | (3 << 14) | (0xf << 3)); - } else { - value &= 7; + if (!arm_feature(env, ARM_FEATURE_V8)) { + if (arm_feature(env, ARM_FEATURE_LPAE) && (value & TTBCR_EAE)) { + /* Pre ARMv8 bits [21:19], [15:14] and [6:3] are UNK/SBZP when + * using Long-desciptor translation table format */ + value &= ~((7 << 19) | (3 << 14) | (0xf << 3)); + } else if (arm_feature(env, ARM_FEATURE_EL3)) { + /* In an implementation that includes the Security Extensions + * TTBCR has additional fields PD0 [4] and PD1 [5] for + * Short-descriptor translation table format. + */ + value &= TTBCR_PD1 | TTBCR_PD0 | TTBCR_N; + } else { + value &= TTBCR_N; + } } + /* Note that we always calculate c2_mask and c2_base_mask, but * they are only used for short-descriptor tables (ie if EAE is 0); * for long-descriptor tables the TTBCR fields are used differently @@ -3540,17 +3551,24 @@ static inline int check_ap(CPUARMState *env, int ap, int domain_prot, } } -static uint32_t get_level1_table_address(CPUARMState *env, uint32_t address) +static bool get_level1_table_address(CPUARMState *env, uint32_t *table, + uint32_t address) { - uint32_t table; - - if (address & env->cp15.c2_mask) - table = env->cp15.ttbr1_el1 & 0xffffc000; - else - table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask; - - table |= (address >> 18) & 0x3ffc; - return table; + if (address & env->cp15.c2_mask) { + if ((env->cp15.c2_control & TTBCR_PD1)) { + /* Translation table walk disabled for TTBR1 */ + return false; + } + *table = env->cp15.ttbr1_el1 & 0xffffc000; + } else { + if ((env->cp15.c2_control & TTBCR_PD0)) { + /* Translation table walk disabled for TTBR0 */ + return false; + } + *table = env->cp15.ttbr0_el1 & env->cp15.c2_base_mask; + } + *table |= (address >> 18) & 0x3ffc; + return true; } static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, @@ -3563,13 +3581,17 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, uint32_t desc; int type; int ap; - int domain; + int domain = 0; int domain_prot; hwaddr phys_addr; /* Pagetable walk. */ /* Lookup l1 descriptor. */ - table = get_level1_table_address(env, address); + if (!get_level1_table_address(env, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + code = 5; + goto do_fault; + } desc = ldl_phys(cs->as, table); type = (desc & 3); domain = (desc >> 5) & 0x0f; @@ -3667,7 +3689,11 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, /* Pagetable walk. */ /* Lookup l1 descriptor. */ - table = get_level1_table_address(env, address); + if (!get_level1_table_address(env, &table, address)) { + /* Section translation fault if page walk is disabled by PD0 or PD1 */ + code = 5; + goto do_fault; + } desc = ldl_phys(cs->as, table); type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { @@ -3926,7 +3952,7 @@ static int 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 = (1 << ((granule_sz * (4 - level)) + 3)); + page_size = (1ULL << ((granule_sz * (4 - level)) + 3)); descaddr |= (address & (page_size - 1)); /* Extract attributes from the descriptor and merge with table attrs */ attrs = extract64(descriptor, 2, 10) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index 39202d7eea..319784d689 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -27,6 +27,17 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { KVM_CAP_LAST_INFO }; +int kvm_arm_vcpu_init(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + struct kvm_vcpu_init init; + + init.target = cpu->kvm_target; + memcpy(init.features, cpu->kvm_init_features, sizeof(init.features)); + + return kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); +} + bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try, int *fdarray, struct kvm_vcpu_init *init) diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index b79750c57e..068af7db57 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -166,7 +166,6 @@ static int compare_u64(const void *a, const void *b) int kvm_arch_init_vcpu(CPUState *cs) { - struct kvm_vcpu_init init; int i, ret, arraylen; uint64_t v; struct kvm_one_reg r; @@ -179,15 +178,22 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } - init.target = cpu->kvm_target; - memset(init.features, 0, sizeof(init.features)); + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); if (cpu->start_powered_off) { - init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF; } - ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); + if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) { + cpu->psci_version = 2; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + } + + /* Do KVM_ARM_VCPU_INIT ioctl */ + ret = kvm_arm_vcpu_init(cs); if (ret) { return ret; } + /* Query the kernel to make sure it supports 32 VFP * registers: QEMU's "cortex-a15" CPU is always a * VFP-D32 core. The simplest way to do this is just diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index 70f311bed6..5d217ca2ad 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -77,9 +77,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) int kvm_arch_init_vcpu(CPUState *cs) { - ARMCPU *cpu = ARM_CPU(cs); - struct kvm_vcpu_init init; int ret; + ARMCPU *cpu = ARM_CPU(cs); if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE || !arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { @@ -87,16 +86,25 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } - init.target = cpu->kvm_target; - memset(init.features, 0, sizeof(init.features)); + /* Determine init features for this CPU */ + memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features)); if (cpu->start_powered_off) { - init.features[0] = 1 << KVM_ARM_VCPU_POWER_OFF; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF; + } + if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) { + cpu->psci_version = 2; + cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + } + + /* Do KVM_ARM_VCPU_INIT ioctl */ + ret = kvm_arm_vcpu_init(cs); + if (ret) { + return ret; } - ret = kvm_vcpu_ioctl(cs, KVM_ARM_VCPU_INIT, &init); /* TODO : support for save/restore/reset of system regs via tuple list */ - return ret; + return 0; } #define AARCH64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ @@ -262,4 +270,8 @@ int kvm_arch_get_registers(CPUState *cs) void kvm_arm_reset_vcpu(ARMCPU *cpu) { + /* Re-init VCPU so that all registers are set to + * their respective reset values. + */ + kvm_arm_vcpu_init(CPU(cpu)); } diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h index dc4e2336fa..af93105517 100644 --- a/target-arm/kvm_arm.h +++ b/target-arm/kvm_arm.h @@ -14,6 +14,18 @@ #include "sysemu/kvm.h" #include "exec/memory.h" +/** + * kvm_arm_vcpu_init: + * @cs: CPUState + * + * Initialize (or reinitialize) the VCPU by invoking the + * KVM_ARM_VCPU_INIT ioctl with the CPU type and feature + * bitmask specified in the CPUState. + * + * Returns: 0 if success else < 0 error code + */ +int kvm_arm_vcpu_init(CPUState *cs); + /** * kvm_arm_register_device: * @mr: memory region for this device diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 63ad787e9f..33b5025fee 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -6539,7 +6539,7 @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar, tcg_shift = tcg_const_i32(fracbits); if (is_double) { - int maxpass = is_scalar ? 1 : is_q ? 2 : 1; + int maxpass = is_scalar ? 1 : 2; for (pass = 0; pass < maxpass; pass++) { TCGv_i64 tcg_op = tcg_temp_new_i64(); @@ -9052,7 +9052,8 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) } if (size == 3) { - for (pass = 0; pass < (is_q ? 2 : 1); pass++) { + assert(is_q); + for (pass = 0; pass < 2; pass++) { TCGv_i64 tcg_op1 = tcg_temp_new_i64(); TCGv_i64 tcg_op2 = tcg_temp_new_i64(); TCGv_i64 tcg_res = tcg_temp_new_i64();