From e389be1673052b538534643165111725a79e5afd Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Thu, 19 Jun 2014 18:06:24 +0100 Subject: [PATCH 01/14] target-arm: implement PD0/PD1 bits for TTBCR Corrected handling of writes to TTBCR for ARMv8 (previously UNK/SBZP bits are not RES0) and ARMv7 (new bits PD0/PD1 for CPUs with Security Extensions). Bits PD0/PD1 are now respected in get_phys_addr_v6/v5() and get_level1_table_address. Signed-off-by: Fabian Aggeler Message-id: 1402409556-18574-1-git-send-email-aggelerf@ethz.ch Signed-off-by: Peter Maydell --- target-arm/cpu.h | 16 ++++++++++++ target-arm/helper.c | 62 ++++++++++++++++++++++++++++++++------------- 2 files changed, 60 insertions(+), 18 deletions(-) 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..12285cdb6c 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))) { From 0062609f70b465a56cf80bc573d0971ef2a0affb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:24 +0100 Subject: [PATCH 02/14] hw/arm/spitz: Avoid clash with Windows header symbol MOD_SHIFT The Windows headers provided by MinGW define MOD_SHIFT. Avoid it by using SPITZ_MOD_* for our constants here. Signed-off-by: Peter Maydell --- hw/arm/spitz.c | 108 ++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 50 deletions(-) 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) { From 5661ae6be23d8831a19c82f8eafb2aaecdf2da6a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:24 +0100 Subject: [PATCH 03/14] target-arm: Add ULL suffix to calculation of page size The maximum block size for AArch64 address translation is 2GB. This means that we need a ULL suffix on our shift to avoid shifting into the sign bit of a signed 32 bit integer. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1402171881-14343-2-git-send-email-peter.maydell@linaro.org --- target-arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 12285cdb6c..ed4d2bb419 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3952,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) From 220ad4ca846d8e0734dd2d2af38c61a6f5436d66 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:24 +0100 Subject: [PATCH 04/14] target-arm/translate-a64.c: Remove dead ?: in disas_simd_3same_int() In disas_simd_3same_int(), none of the instructions permit is_q to be false with size == 3 (this would be a vector operation with a one-element vector, and the instruction set encodes those as scalar operations). Replace the always-true ?: check with an assert. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1402171881-14343-3-git-send-email-peter.maydell@linaro.org --- target-arm/translate-a64.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 63ad787e9f..cbc8a3574d 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -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(); From 4063452eca8aaa432b5c42b1ccea81be01219b0e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:25 +0100 Subject: [PATCH 05/14] target-arm/translate-a64.c: Fix dead ?: in handle_simd_shift_fpint_conv() In handle_simd_shift_fpint_conv(), the combination of is_double == true, is_scalar == false and is_q == false is an unallocated encoding; the 'both parts false' case of the nested ?: expression for calculating maxpass is therefore unreachable and can be removed. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1402171881-14343-4-git-send-email-peter.maydell@linaro.org --- target-arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index cbc8a3574d..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(); From 476e75ab9d2cf2ad8ac8dfd9530c9fee148c2c7a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:25 +0100 Subject: [PATCH 06/14] hw/arm/vexpress: Forbid specifying flash contents in two ways at once Detect attempts by the user to specify the contents of the first flash device via both -bios and -drive if=pflash... simultaneously and print a helpful error message. Signed-off-by: Peter Maydell Message-id: 1402419834-25982-1-git-send-email-peter.maydell@linaro.org --- hw/arm/vexpress.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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); From a0289b8af3b05fe47bee8e434d1c978382a5a8cc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 Jun 2014 18:06:25 +0100 Subject: [PATCH 07/14] hw/block/pflash_cfi01: Report correct size info for parallel configs If the flash device is configured with a device-width which is not equal to the bank-width, indicating that it is actually several narrow flash devices in parallel, the CFI table should report the number of blocks and the size of a single device, not of the whole combined setup. This stops Linux from complaining: "NOR chip too large to fit in mapping. Attempting to cope..." As usual, we retain the old broken but backwards compatible behaviour when the device-width is not specified. Reviewed-by: Peter Crosthwaite Signed-off-by: Peter Maydell Message-id: 1402409025-25694-1-git-send-email-peter.maydell@linaro.org --- hw/block/pflash_cfi01.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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. From 99040447cee777498c1b2125f16402b8af88355c Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:25 +0100 Subject: [PATCH 08/14] kvm: Handle exit reason KVM_EXIT_SYSTEM_EVENT In-kernel PSCI v0.2 emulation of KVM ARM/ARM64 forwards SYSTEM_OFF and SYSTEM_RESET function calls to QEMU using KVM_EXIT_SYSTEM_EVENT exit reason. This patch updates kvm_cpu_exec() to handle KVM_SYSTEM_EVENT_SHUTDOWN and KVM_SYSTEM_EVENT_RESET system-level events from QEMU-side. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Peter Maydell Message-id: 1402901605-24551-4-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- kvm-all.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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); From 228d5e048b68672593d93f1e42d777de80903e3d Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:26 +0100 Subject: [PATCH 09/14] target-arm: Common kvm_arm_vcpu_init() for KVM ARM and KVM ARM64 Introduce a common kvm_arm_vcpu_init() for doing KVM_ARM_VCPU_INIT ioctl in KVM ARM and KVM ARM64. This also helps us factor-out few common code lines from kvm_arch_init_vcpu() for KVM ARM/ARM64. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Peter Maydell Message-id: 1402901605-24551-5-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 3 +++ target-arm/kvm.c | 11 +++++++++++ target-arm/kvm32.c | 12 +++++++----- target-arm/kvm64.c | 18 +++++++++++------- target-arm/kvm_arm.h | 12 ++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index edc7f262fc..2bd7df8bfd 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -102,6 +102,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/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..b142e90719 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,18 @@ 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); + + /* 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..9936aa85a8 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,21 @@ 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; + } + + /* 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 | \ 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 From 7cd62e53844603357152943f68960c8c5279160c Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:26 +0100 Subject: [PATCH 10/14] target-arm: Enable KVM_ARM_VCPU_PSCI_0_2 feature when possible Latest linux kernel supports in-kernel emulation of PSCI v0.2 but to enable it we need to select KVM_ARM_VCPU_PSCI_0_2 feature using KVM_ARM_VCPU_INIT ioctl. Also, we can use KVM_ARM_VCPU_PSCI_0_2 feature for VCPU only when linux kernel has KVM_CAP_ARM_PSCI_0_2 capability. This patch updates kvm_arch_init_vcpu() to enable KVM_ARM_VCPU_PSCI_0_2 feature for VCPU when KVM ARM/ARM64 has KVM_CAP_ARM_PSCI_0_2 capability. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Peter Maydell Message-id: 1402901605-24551-6-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- target-arm/kvm32.c | 3 +++ target-arm/kvm64.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index b142e90719..52d626c476 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -183,6 +183,9 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->start_powered_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->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + } /* Do KVM_ARM_VCPU_INIT ioctl */ ret = kvm_arm_vcpu_init(cs); diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index 9936aa85a8..828ffb6891 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -91,6 +91,9 @@ int kvm_arch_init_vcpu(CPUState *cs) if (cpu->start_powered_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->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2; + } /* Do KVM_ARM_VCPU_INIT ioctl */ ret = kvm_arm_vcpu_init(cs); From 73542cf6900146f4a203007388e224e5dc25c7da Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:26 +0100 Subject: [PATCH 11/14] target-arm: Implement kvm_arch_reset_vcpu() for KVM ARM64 To implement kvm_arch_reset_vcpu(), we simply re-init the VCPU using kvm_arm_vcpu_init() so that all registers of VCPU are set to their reset values by in-kernel KVM code. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Peter Maydell Message-id: 1402901605-24551-7-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- target-arm/kvm64.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index 828ffb6891..fca5f587e2 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -269,4 +269,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)); } From dd032e348757bae0451e25a473f34c25f8750c2b Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:26 +0100 Subject: [PATCH 12/14] target-arm: Introduce per-CPU field for PSCI version We require to know the PSCI version available to given CPU at potentially many places. Currently, we need to know PSCI version when generating DTB for virt machine. This patch introduce per-CPU 32bit field representing the PSCI version available to the CPU. The encoding of this 32bit field is same as described in PSCI v0.2 spec. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Peter Maydell Message-id: 1402901605-24551-8-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 6 ++++++ target-arm/cpu.c | 1 + target-arm/kvm32.c | 1 + target-arm/kvm64.c | 1 + 4 files changed, 9 insertions(+) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 2bd7df8bfd..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; 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/kvm32.c b/target-arm/kvm32.c index 52d626c476..068af7db57 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -184,6 +184,7 @@ int kvm_arch_init_vcpu(CPUState *cs) 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; } diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index fca5f587e2..5d217ca2ad 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -92,6 +92,7 @@ int kvm_arch_init_vcpu(CPUState *cs) 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; } From 06955739a283ecaf9e2c7658cd9d471e9967cac4 Mon Sep 17 00:00:00 2001 From: Pranavkumar Sawargaonkar Date: Thu, 19 Jun 2014 18:06:27 +0100 Subject: [PATCH 13/14] Use PSCI v0.2 compatible string when KVM or TCG provides it If we have PSCI v0.2 emulation available for KVM ARM/ARM64 or TCG then we need to provide PSCI v0.2 compatible string via generated DTB. Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Anup Patel Reviewed-by: Rob Herring Message-id: 1402901605-24551-9-git-send-email-pranavkumar@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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); From b6fb3a89e3cd173153f1edc4edbf970987b4ebdd Mon Sep 17 00:00:00 2001 From: Oran Avraham Date: Thu, 19 Jun 2014 18:06:27 +0100 Subject: [PATCH 14/14] armv7m_nvic: fix AIRCR implementation The returned reset value was wrong (off by one zero nibble), and qemu didn't log unimplemented writes to the PRIGROUP field. Signed-off-by: Oran Avraham Message-id: 1403010447-4627-1-git-send-email-oranav@gmail.com Signed-off-by: Peter Maydell --- hw/intc/armv7m_nvic.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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. */