From cfd54a0409c92cbf3b2e6af39ce44a13f6940dd0 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Sun, 16 Mar 2014 14:49:54 +0100 Subject: [PATCH 01/13] target-ppc: Add missing 'static' and 'const' attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes warnings from the static code analysis (smatch). Signed-off-by: Stefan Weil Signed-off-by: Andreas Färber --- target-ppc/arch_dump.c | 6 +++--- target-ppc/int_helper.c | 2 +- target-ppc/machine.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target-ppc/arch_dump.c b/target-ppc/arch_dump.c index 17fd4c6fb1..9dccf1ae1f 100644 --- a/target-ppc/arch_dump.c +++ b/target-ppc/arch_dump.c @@ -164,7 +164,7 @@ static void ppc64_write_elf64_speregset(Note *note, PowerPCCPU *cpu) speregset->spe_fscr = cpu_to_be32(cpu->env.spe_fscr); } -struct NoteFuncDescStruct { +static const struct NoteFuncDescStruct { int contents_size; void (*note_contents_func)(Note *note, PowerPCCPU *cpu); } note_func[] = { @@ -196,7 +196,7 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) int name_size = 8; /* "CORE" or "QEMU" rounded */ size_t elf_note_size = 0; int note_head_size; - NoteFuncDesc *nf; + const NoteFuncDesc *nf; if (class != ELFCLASS64) { return -1; @@ -221,7 +221,7 @@ static int ppc64_write_all_elf64_notes(const char *note_name, Note note; int ret = -1; int note_size; - NoteFuncDesc *nf; + const NoteFuncDesc *nf; for (nf = note_func; nf->note_contents_func; nf++) { note.hdr.n_namesz = cpu_to_be32(sizeof(note.name)); diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c index e14e304457..18b54f060a 100644 --- a/target-ppc/int_helper.c +++ b/target-ppc/int_helper.c @@ -1075,7 +1075,7 @@ void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #undef VBPERMQ_INDEX #undef VBPERMQ_DW -uint64_t VGBBD_MASKS[256] = { +static const uint64_t VGBBD_MASKS[256] = { 0x0000000000000000ull, /* 00 */ 0x0000000000000080ull, /* 01 */ 0x0000000000008000ull, /* 02 */ diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 2d46ceccca..063b379d90 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -114,7 +114,7 @@ static void put_avr(QEMUFile *f, void *pv, size_t size) qemu_put_be64(f, v->u64[1]); } -const VMStateInfo vmstate_info_avr = { +static const VMStateInfo vmstate_info_avr = { .name = "avr", .get = get_avr, .put = put_avr, @@ -288,7 +288,7 @@ static void put_slbe(QEMUFile *f, void *pv, size_t size) qemu_put_be64(f, v->vsid); } -const VMStateInfo vmstate_info_slbe = { +static const VMStateInfo vmstate_info_slbe = { .name = "slbe", .get = get_slbe, .put = put_slbe, From 7aaf4957efad2bf6ac449d0caa9a1535f61006bc Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Fri, 14 Mar 2014 19:21:49 +0530 Subject: [PATCH 02/13] spapr_hcall: Fix h_enter to loop correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We wanted to loop till index is 8. On 8 we return with H_PTEG_FULL. If we are successful in loading hpte with any other index, we continue with that index value. Reported-by: Paolo Bonzini Signed-off-by: Aneesh Kumar K.V Reviewed-by: Paolo Bonzini Signed-off-by: Andreas Färber --- hw/ppc/spapr_hcall.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e999bbaea0..2ab55d568b 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -110,16 +110,15 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, if (likely((flags & H_EXACT) == 0)) { pte_index &= ~7ULL; token = ppc_hash64_start_access(cpu, pte_index); - do { - if (index == 8) { - ppc_hash64_stop_access(token); - return H_PTEG_FULL; - } + for (; index < 8; index++) { if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) { break; } - } while (index++); + } ppc_hash64_stop_access(token); + if (index == 8) { + return H_PTEG_FULL; + } } else { token = ppc_hash64_start_access(cpu, pte_index); if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) { From d197fdbc3b83655f3c145722805f0998c04dce16 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 20 Mar 2014 00:03:57 +1100 Subject: [PATCH 03/13] target-ppc: Reset SPRs on CPU reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This resets SPR values to defaults on CPU reset. This should help with little-endian guests reboot issues. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Signed-off-by: Andreas Färber --- target-ppc/cpu.h | 1 + target-ppc/translate_init.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 91b7ae5534..8c181e7245 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -334,6 +334,7 @@ struct ppc_spr_t { void (*hea_write)(void *opaque, int spr_num, int gpr_num); #endif const char *name; + target_ulong default_value; #ifdef CONFIG_KVM /* We (ab)use the fact that all the SPRs will have ids for the * ONE_REG interface will have KVM_REG_PPC to use 0 as meaning, diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 6084f40f28..954dee3ec2 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -631,7 +631,7 @@ static inline void _spr_register(CPUPPCState *env, int num, #if defined(CONFIG_KVM) spr->one_reg_id = one_reg_id, #endif - env->spr[num] = initial_value; + env->spr[num] = spr->default_value = initial_value; } /* Generic PowerPC SPRs */ @@ -8381,6 +8381,7 @@ static void ppc_cpu_reset(CPUState *s) PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; target_ulong msr; + int i; pcc->parent_reset(s); @@ -8434,6 +8435,15 @@ static void ppc_cpu_reset(CPUState *s) env->dtl_size = 0; #endif /* TARGET_PPC64 */ + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (!spr->name) { + continue; + } + env->spr[i] = spr->default_value; + } + /* Flush all TLBs */ tlb_flush(s, 1); } From a80172a4762465a40f6b59d10d64360bd272b700 Mon Sep 17 00:00:00 2001 From: Stuart Brady Date: Wed, 19 Mar 2014 14:07:26 +0000 Subject: [PATCH 04/13] target-ppc: Fix overallocation of opcode tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create_new_table() should allocate 0x20 opc_handler_t pointers, but actually allocates 0x20 opc_handler_t structs. Fix this. Signed-off-by: Stuart Brady Reviewed-by: Tom Musta Tested-by: Tom Musta Signed-off-by: Andreas Färber --- target-ppc/translate_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 954dee3ec2..3269c3ebe4 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7434,7 +7434,7 @@ static int create_new_table (opc_handler_t **table, unsigned char idx) { opc_handler_t **tmp; - tmp = g_malloc(0x20 * sizeof(opc_handler_t)); + tmp = g_new(opc_handler_t *, 0x20); fill_new_table(tmp, 0x20); table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); From 5ec83c73e5ece590538878b24dfcb422904533e0 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Wed, 5 Mar 2014 14:02:36 +0530 Subject: [PATCH 05/13] target-ppc: Force CPU threads count to be a power of 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PowerPC kernel expects the number of SMT threads in a core to be a power of 2. Since QEMU doesn't enforce this, it leads to an early guest kernel crash if invalid threads count is specified. Prevent this crash and make it a graceful exit from QEMU itself by validating the user-supplied threads count. Signed-off-by: Bharata B Rao Reviewed-by: Eric Blake Reviewed-by: Stewart Smith Signed-off-by: Andreas Färber --- target-ppc/translate_init.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3269c3ebe4..5302bdc1b2 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7848,6 +7848,12 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) max_smt, kvm_enabled() ? "KVM" : "TCG"); return; } + if (!is_power_of_2(smp_threads)) { + error_setg(errp, "Cannot support %d threads on PPC with %s, " + "threads count must be a power of 2.", + smp_threads, kvm_enabled() ? "KVM" : "TCG"); + return; + } cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt + (cs->cpu_index % smp_threads); From df99d30d4e0dd22be5572235a5213de429e00747 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 7 Mar 2014 15:37:39 +1100 Subject: [PATCH 06/13] target-ppc: Introduce powerisa-207-server flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This flag will be used to decide whether to emulate some bits of H_SET_MODE hypercall because some are POWER8-only. While we are here, add 2.05 flag to POWER8 family too. POWER7/7+ already have it. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Signed-off-by: Andreas Färber --- target-ppc/cpu.h | 2 ++ target-ppc/translate_init.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 8c181e7245..2719c08323 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -1901,6 +1901,8 @@ enum { PPC2_LSQ_ISA207 = 0x0000000000002000ULL, /* ISA 2.07 Altivec */ PPC2_ALTIVEC_207 = 0x0000000000004000ULL, + /* PowerISA 2.07 Book3s specification */ + PPC2_ISA207S = 0x0000000000008000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 5302bdc1b2..7f53c33eaf 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -7173,7 +7173,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | - PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207; + PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | + PPC2_ISA205 | PPC2_ISA207S; pcc->msr_mask = 0x800000000284FF36ULL; pcc->mmu_model = POWERPC_MMU_2_06; #if defined(CONFIG_SOFTMMU) From a46622fd07edc6fd3c66f8ab79b4782a78b115f3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 7 Mar 2014 15:37:40 +1100 Subject: [PATCH 07/13] spapr_hcall: Fix little-endian resource handling in H_SET_MODE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes resource code definitions to ones used in the host kernel. This fixes H_SET_MODE_RESOURCE_LE (switch between big endian and little endian) to sync registers from KVM before changing LPCR value. This adds a set_spr() helper to update an SPR in a CPU's context to avoid possible races and makes use of it to change LPCR. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Greg Kurz Signed-off-by: Andreas Färber --- hw/ppc/spapr_hcall.c | 41 +++++++++++++++++++++++++++++++++-------- include/hw/ppc/spapr.h | 9 +++++++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 2ab55d568b..0bae0535e8 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -4,6 +4,36 @@ #include "hw/ppc/spapr.h" #include "mmu-hash64.h" +struct SPRSyncState { + CPUState *cs; + int spr; + target_ulong value; + target_ulong mask; +}; + +static void do_spr_sync(void *arg) +{ + struct SPRSyncState *s = arg; + PowerPCCPU *cpu = POWERPC_CPU(s->cs); + CPUPPCState *env = &cpu->env; + + cpu_synchronize_state(s->cs); + env->spr[s->spr] &= ~s->mask; + env->spr[s->spr] |= s->value; +} + +static void set_spr(CPUState *cs, int spr, target_ulong value, + target_ulong mask) +{ + struct SPRSyncState s = { + .cs = cs, + .spr = spr, + .value = value, + .mask = mask + }; + run_on_cpu(cs, do_spr_sync, &s); +} + static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r, target_ulong pte_index) { @@ -689,7 +719,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong value2 = args[3]; target_ulong ret = H_P2; - if (resource == H_SET_MODE_ENDIAN) { + if (resource == H_SET_MODE_RESOURCE_LE) { if (value1) { ret = H_P3; goto out; @@ -698,22 +728,17 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr, ret = H_P4; goto out; } - switch (mflags) { case H_SET_MODE_ENDIAN_BIG: CPU_FOREACH(cs) { - PowerPCCPU *cp = POWERPC_CPU(cs); - CPUPPCState *env = &cp->env; - env->spr[SPR_LPCR] &= ~LPCR_ILE; + set_spr(cs, SPR_LPCR, 0, LPCR_ILE); } ret = H_SUCCESS; break; case H_SET_MODE_ENDIAN_LITTLE: CPU_FOREACH(cs) { - PowerPCCPU *cp = POWERPC_CPU(cs); - CPUPPCState *env = &cp->env; - env->spr[SPR_LPCR] |= LPCR_ILE; + set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE); } ret = H_SUCCESS; break; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 449fc7ca2d..5fdac1e009 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -153,8 +153,13 @@ typedef struct sPAPREnvironment { #define H_PP1 (1ULL<<(63-62)) #define H_PP2 (1ULL<<(63-63)) -/* H_SET_MODE flags */ -#define H_SET_MODE_ENDIAN 4 +/* Values for 2nd argument to H_SET_MODE */ +#define H_SET_MODE_RESOURCE_SET_CIABR 1 +#define H_SET_MODE_RESOURCE_SET_DAWR 2 +#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 +#define H_SET_MODE_RESOURCE_LE 4 + +/* Flags for H_SET_MODE_RESOURCE_LE */ #define H_SET_MODE_ENDIAN_BIG 0 #define H_SET_MODE_ENDIAN_LITTLE 1 From 30e32af7466841f5fc08a5339e2184884a7bc6f3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 17 Mar 2014 13:40:22 +1100 Subject: [PATCH 08/13] vl.c: Extend get_boot_devices_list() to ignore suffixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As suffixes do not make sense for sPAPR's device tree and there is no way to filter them out on the BusState::get_fw_dev_path() level, let's add an ability for the external caller to specify whether to apply suffixes or not. We could handle suffixes in SLOF (ignored for now) but this would require serious rework in the node opening code in SLOF, which has no obvious benefit for the currently emulated sPAPR machine. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/nvram/fw_cfg.c | 2 +- include/sysemu/sysemu.h | 2 +- vl.c | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index cb36dc2d0c..282341ac1b 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -504,7 +504,7 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data) { size_t len; FWCfgState *s = container_of(n, FWCfgState, machine_ready); - char *bootindex = get_boot_devices_list(&len); + char *bootindex = get_boot_devices_list(&len, false); fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len); } diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index c01304d39a..3915ce3204 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -186,7 +186,7 @@ void rtc_change_mon_event(struct tm *tm); void add_boot_device_path(int32_t bootindex, DeviceState *dev, const char *suffix); -char *get_boot_devices_list(size_t *size); +char *get_boot_devices_list(size_t *size, bool ignore_suffixes); DeviceState *get_boot_device(uint32_t position); diff --git a/vl.c b/vl.c index f0fe48b106..1adc8f4e40 100644 --- a/vl.c +++ b/vl.c @@ -1209,7 +1209,7 @@ DeviceState *get_boot_device(uint32_t position) * memory pointed by "size" is assigned total length of the array in bytes * */ -char *get_boot_devices_list(size_t *size) +char *get_boot_devices_list(size_t *size, bool ignore_suffixes) { FWBootEntry *i; size_t total = 0; @@ -1224,7 +1224,7 @@ char *get_boot_devices_list(size_t *size) assert(devpath); } - if (i->suffix && devpath) { + if (i->suffix && !ignore_suffixes && devpath) { size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1; bootpath = g_malloc(bootpathlen); @@ -1232,9 +1232,11 @@ char *get_boot_devices_list(size_t *size) g_free(devpath); } else if (devpath) { bootpath = devpath; - } else { + } else if (!ignore_suffixes) { assert(i->suffix); bootpath = g_strdup(i->suffix); + } else { + bootpath = g_strdup(""); } if (total) { From 6b1566cbe372660c77ca4aa7aa0071fa30f5f930 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Mar 2014 13:40:23 +1100 Subject: [PATCH 09/13] qdev: Introduce FWPathProvider interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU supports firmware names for all devices in the QEMU tree but some architectures expect some parts of firmware path names in different format. This introduces a firmware-pathname-change interface definition. If some machines needs to redefine the firmware path format, it has to add the TYPE_FW_PATH_PROVIDER interface to an object that is above the device on the QOM tree (typically /machine). Signed-off-by: Paolo Bonzini Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/core/Makefile.objs | 1 + hw/core/fw-path-provider.c | 51 +++++++++++++++++++++++++++++++++++ hw/core/qdev.c | 18 ++++++++++++- include/hw/fw-path-provider.h | 47 ++++++++++++++++++++++++++++++++ tests/Makefile | 1 + 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 hw/core/fw-path-provider.c create mode 100644 include/hw/fw-path-provider.h diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 981593c7e6..5377d052e9 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -1,5 +1,6 @@ # core qdev-related obj files, also used by *-user: common-obj-y += qdev.o qdev-properties.o +common-obj-y += fw-path-provider.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o common-obj-y += hotplug.o diff --git a/hw/core/fw-path-provider.c b/hw/core/fw-path-provider.c new file mode 100644 index 0000000000..b11715733d --- /dev/null +++ b/hw/core/fw-path-provider.c @@ -0,0 +1,51 @@ +/* + * Firmware patch provider class and helpers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "hw/fw-path-provider.h" + +char *fw_path_provider_get_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev) +{ + FWPathProviderClass *k = FW_PATH_PROVIDER_GET_CLASS(p); + + return k->get_dev_path(p, bus, dev); +} + +char *fw_path_provider_try_get_dev_path(Object *o, BusState *bus, + DeviceState *dev) +{ + FWPathProvider *p = (FWPathProvider *) + object_dynamic_cast(o, TYPE_FW_PATH_PROVIDER); + + if (p) { + return fw_path_provider_get_dev_path(p, bus, dev); + } + + return NULL; +} + +static const TypeInfo fw_path_provider_info = { + .name = TYPE_FW_PATH_PROVIDER, + .parent = TYPE_INTERFACE, + .class_size = sizeof(FWPathProviderClass), +}; + +static void fw_path_provider_register_types(void) +{ + type_register_static(&fw_path_provider_info); +} + +type_init(fw_path_provider_register_types) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 9f0a522ee8..cd09cd4d95 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -26,6 +26,7 @@ this API directly. */ #include "hw/qdev.h" +#include "hw/fw-path-provider.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qapi/qmp/qerror.h" @@ -568,6 +569,18 @@ static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) return NULL; } +static char *qdev_get_fw_dev_path_from_handler(BusState *bus, DeviceState *dev) +{ + Object *obj = OBJECT(dev); + char *d = NULL; + + while (!d && obj->parent) { + obj = obj->parent; + d = fw_path_provider_try_get_dev_path(obj, bus, dev); + } + return d; +} + static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) { int l = 0; @@ -575,7 +588,10 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) if (dev && dev->parent_bus) { char *d; l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size); - d = bus_get_fw_dev_path(dev->parent_bus, dev); + d = qdev_get_fw_dev_path_from_handler(dev->parent_bus, dev); + if (!d) { + d = bus_get_fw_dev_path(dev->parent_bus, dev); + } if (d) { l += snprintf(p + l, size - l, "%s", d); g_free(d); diff --git a/include/hw/fw-path-provider.h b/include/hw/fw-path-provider.h new file mode 100644 index 0000000000..301834972c --- /dev/null +++ b/include/hw/fw-path-provider.h @@ -0,0 +1,47 @@ +/* + * Firmware patch provider class and helpers definitions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; under version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef FW_PATH_PROVIDER_H +#define FW_PATH_PROVIDER_H 1 + +#include "qemu-common.h" +#include "qom/object.h" + +#define TYPE_FW_PATH_PROVIDER "fw-path-provider" + +#define FW_PATH_PROVIDER_CLASS(klass) \ + OBJECT_CLASS_CHECK(FWPathProviderClass, (klass), TYPE_FW_PATH_PROVIDER) +#define FW_PATH_PROVIDER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(FWPathProviderClass, (obj), TYPE_FW_PATH_PROVIDER) +#define FW_PATH_PROVIDER(obj) \ + INTERFACE_CHECK(FWPathProvider, (obj), TYPE_FW_PATH_PROVIDER) + +typedef struct FWPathProvider { + Object parent_obj; +} FWPathProvider; + +typedef struct FWPathProviderClass { + InterfaceClass parent_class; + + char *(*get_dev_path)(FWPathProvider *p, BusState *bus, DeviceState *dev); +} FWPathProviderClass; + +char *fw_path_provider_get_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev); +char *fw_path_provider_try_get_dev_path(Object *o, BusState *bus, + DeviceState *dev); + +#endif /* FW_PATH_PROVIDER_H */ diff --git a/tests/Makefile b/tests/Makefile index 471b4c8785..2d021fb16d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -206,6 +206,7 @@ tests/test-int128$(EXESUF): tests/test-int128.o tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\ hw/core/irq.o \ + hw/core/fw-path-provider.o \ $(qom-core-obj) \ $(test-qapi-obj-y) \ libqemuutil.a libqemustub.a From ad4f62d0159fa2967195d095e7b532b9497fa6b0 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 17 Mar 2014 13:40:24 +1100 Subject: [PATCH 10/13] spapr_llan: Add to boot device list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/net/spapr_llan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index f6fbcb56bf..c433337b67 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -29,6 +29,7 @@ #include "hw/qdev.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" +#include "sysemu/sysemu.h" #include @@ -213,6 +214,8 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev) object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a); + add_boot_device_path(dev->nicconf.bootindex, DEVICE(dev), ""); + return 0; } From 5a06393f1d7edc6274233533aac99a5ded1785ce Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 17 Mar 2014 13:40:25 +1100 Subject: [PATCH 11/13] spapr_vio: Fix firmware names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes VIO bridge fw name from spapr-vio-bridge to vdevice and vscsi/veth node names from QEMU object names to VIO specific device tree names. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/ppc/spapr_vio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 4e33f462d9..2ae06a3356 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -68,6 +68,7 @@ static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) BusClass *k = BUS_CLASS(klass); k->get_dev_path = spapr_vio_get_dev_name; + k->get_fw_dev_path = spapr_vio_get_dev_name; } static const TypeInfo spapr_vio_bus_info = { @@ -529,7 +530,9 @@ static int spapr_vio_bridge_init(SysBusDevice *dev) static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + dc->fw_name = "vdevice"; k->init = spapr_vio_bridge_init; } From 29ee324740fa7af4b7cf0ce9295a07296e9a0f24 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 17 Mar 2014 13:40:26 +1100 Subject: [PATCH 12/13] spapr: QOM'ify pseries machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/ppc/spapr.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5c9a154d6a..170e08383b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -81,6 +81,8 @@ #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) +#define TYPE_SPAPR_MACHINE "spapr-machine" + sPAPREnvironment *spapr; int spapr_allocate_irq(int hint, bool lsi) @@ -1410,9 +1412,23 @@ static QEMUMachine spapr_machine = { .kvm_type = spapr_kvm_type, }; -static void spapr_machine_init(void) +static void spapr_machine_class_init(ObjectClass *oc, void *data) { - qemu_register_machine(&spapr_machine); + MachineClass *mc = MACHINE_CLASS(oc); + + mc->qemu_machine = data; } -machine_init(spapr_machine_init); +static const TypeInfo spapr_machine_info = { + .name = TYPE_SPAPR_MACHINE, + .parent = TYPE_MACHINE, + .class_init = spapr_machine_class_init, + .class_data = &spapr_machine, +}; + +static void spapr_machine_register_types(void) +{ + type_register_static(&spapr_machine_info); +} + +type_init(spapr_machine_register_types) From 71461b0fef53467d2a85dbd72304dba0e01d8370 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 17 Mar 2014 13:40:27 +1100 Subject: [PATCH 13/13] spapr: Implement interface to fix device pathname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This extends the pseries machine type with the interface to fix firmware pathnames for devices which have @bootindex property. This fixes SCSI disks' device node names (which are wildcard nodes in the device-tree), for spapr-vscsi, virtio-scsi and usb-storage. This fixes PHB name from "pci" to "pci@XXXX" where XXXX is a BUID as there is no bus on top of sPAPRPHBState where PHB firmware name could be fixed using the BusClass::get_fw_dev_path() mechanism. This stores the boot list in the /chosen/qemu,boot-list property of the device tree. "\n" are replaced by spaces to support OF1275. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Andreas Färber --- hw/ppc/spapr.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 170e08383b..a11e1217b9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -26,6 +26,7 @@ */ #include "sysemu/sysemu.h" #include "hw/hw.h" +#include "hw/fw-path-provider.h" #include "elf.h" #include "net/net.h" #include "sysemu/blockdev.h" @@ -45,6 +46,8 @@ #include "hw/pci/msi.h" #include "hw/pci/pci.h" +#include "hw/scsi/scsi.h" +#include "hw/virtio/virtio-scsi.h" #include "exec/address-spaces.h" #include "hw/usb.h" @@ -600,7 +603,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, hwaddr rtas_addr, hwaddr rtas_size) { - int ret; + int ret, i; + size_t cb = 0; + char *bootlist; void *fdt; sPAPRPHBState *phb; @@ -642,6 +647,21 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } + bootlist = get_boot_devices_list(&cb, true); + if (cb && bootlist) { + int offset = fdt_path_offset(fdt, "/chosen"); + if (offset < 0) { + exit(1); + } + for (i = 0; i < cb; i++) { + if (bootlist[i] == '\n') { + bootlist[i] = ' '; + } + + } + ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist); + } + if (!spapr->has_graphics) { spapr_populate_chosen_stdout(fdt, spapr->vio_bus); } @@ -1412,11 +1432,70 @@ static QEMUMachine spapr_machine = { .kvm_type = spapr_kvm_type, }; +/* + * Implementation of an interface to adjust firmware patch + * for the bootindex property handling. + */ +static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, + DeviceState *dev) +{ +#define CAST(type, obj, name) \ + ((type *)object_dynamic_cast(OBJECT(obj), (name))) + SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE); + sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE); + + if (d) { + void *spapr = CAST(void, bus->parent, "spapr-vscsi"); + VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI); + USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE); + + if (spapr) { + /* + * Replace "channel@0/disk@0,0" with "disk@8000000000000000": + * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun + * in the top 16 bits of the 64-bit LUN + */ + unsigned id = 0x8000 | (d->id << 8) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 48); + } else if (virtio) { + /* + * We use SRP luns of the form 01000000 | (target << 8) | lun + * in the top 32 bits of the 64-bit LUN + * Note: the quote above is from SLOF and it is wrong, + * the actual binding is: + * swap 0100 or 10 << or 20 << ( target lun-id -- srplun ) + */ + unsigned id = 0x1000000 | (d->id << 16) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 32); + } else if (usb) { + /* + * We use SRP luns of the form 01000000 | (usb-port << 16) | lun + * in the top 32 bits of the 64-bit LUN + */ + unsigned usb_port = atoi(usb->port->path); + unsigned id = 0x1000000 | (usb_port << 16) | d->lun; + return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), + (uint64_t)id << 32); + } + } + + if (phb) { + /* Replace "pci" with "pci@800000020000000" */ + return g_strdup_printf("pci@%"PRIX64, phb->buid); + } + + return NULL; +} + static void spapr_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); + FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); mc->qemu_machine = data; + fwc->get_dev_path = spapr_get_fw_dev_path; } static const TypeInfo spapr_machine_info = { @@ -1424,6 +1503,10 @@ static const TypeInfo spapr_machine_info = { .parent = TYPE_MACHINE, .class_init = spapr_machine_class_init, .class_data = &spapr_machine, + .interfaces = (InterfaceInfo[]) { + { TYPE_FW_PATH_PROVIDER }, + { } + }, }; static void spapr_machine_register_types(void)