diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2011-05-14 16:54:59 +0200 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2011-05-14 16:54:59 +0200 |
commit | 091959defe5856d1ac52dc4c33ed01921484fbf8 (patch) | |
tree | dd0eadc477f7eb5efe9affb9bdbf3fc187d9e2b7 /hw | |
parent | 86f1f2aee8fa8dd6f25ead09433fa0c888db6d37 (diff) | |
parent | be13cc7a352b74412374a554a15b32b105f6706b (diff) |
Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
* 'ppc-next' of git://repo.or.cz/qemu/agraf:
PPC: Qdev'ify e500 pci
PPC MPC7544DS: Use new TLB helper function
PPC: Implement e500 (FSL) MMU
PPC: Add another 64 bits to instruction feature mask
PPC: Add GS MSR definition
PPC: Make MPC8544DS emulation work w/o KVM
PPC: Make MPC8544DS obey -cpu switch
Fix off-by-one error in sizing pSeries hcall table
ppc64: Fix out-of-tree builds
kvm: ppc: warn user on PAGE_SIZE mismatch
kvm: ppc: detect old headers
monitor: add PPC BookE SPRs
kvm: ppc: fixes for KVM_SET_SREGS on init
ppc64: Don't try to build sPAPR RTAS on Darwin
Place pseries vty devices at addresses more similar to existing machines
Make pSeries 'model' property more closely resemble real hardware
pseries: Increase maximum CPUs to 256
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ppc.c | 12 | ||||
-rw-r--r-- | hw/ppce500.h | 22 | ||||
-rw-r--r-- | hw/ppce500_mpc8544ds.c | 113 | ||||
-rw-r--r-- | hw/ppce500_pci.c | 136 | ||||
-rw-r--r-- | hw/spapr.c | 9 | ||||
-rw-r--r-- | hw/spapr_hcall.c | 4 | ||||
-rw-r--r-- | hw/spapr_rtas.c | 3 | ||||
-rw-r--r-- | hw/spapr_vio.h | 2 |
8 files changed, 186 insertions, 115 deletions
@@ -452,6 +452,10 @@ uint64_t cpu_ppc_load_tbl (CPUState *env) ppc_tb_t *tb_env = env->tb_env; uint64_t tb; + if (kvm_enabled()) { + return env->spr[SPR_TBL]; + } + tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset); LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb); @@ -471,6 +475,10 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUState *env) uint32_t cpu_ppc_load_tbu (CPUState *env) { + if (kvm_enabled()) { + return env->spr[SPR_TBU]; + } + return _cpu_ppc_load_tbu(env); } @@ -616,6 +624,10 @@ uint32_t cpu_ppc_load_decr (CPUState *env) { ppc_tb_t *tb_env = env->tb_env; + if (kvm_enabled()) { + return env->spr[SPR_DECR]; + } + return _cpu_ppc_load_decr(env, tb_env->decr_next); } diff --git a/hw/ppce500.h b/hw/ppce500.h deleted file mode 100644 index 24d49bb871..0000000000 --- a/hw/ppce500.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * QEMU PowerPC E500 emulation shared definitions - * - * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Yu Liu, <yu.liu@freescale.com> - * - * This file is derived from hw/ppc440.h - * the copyright for that material belongs to the original owners. - * - * This 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; either version 2 of the License, or - * (at your option) any later version. - */ - -#if !defined(PPC_E500_H) -#define PPC_E500_H - -PCIBus *ppce500_pci_init(qemu_irq *pic, target_phys_addr_t registers); - -#endif /* !defined(PPC_E500_H) */ diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index e111dda5f4..17b0165533 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -28,9 +28,10 @@ #include "kvm_ppc.h" #include "device_tree.h" #include "openpic.h" -#include "ppce500.h" +#include "ppc.h" #include "loader.h" #include "elf.h" +#include "sysbus.h" #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" #define UIMAGE_LOAD_BASE 0 @@ -50,6 +51,12 @@ #define MPC8544_PCI_IO 0xE1000000 #define MPC8544_PCI_IOLEN 0x10000 +struct boot_info +{ + uint32_t dt_base; + uint32_t entry; +}; + #ifdef CONFIG_FDT static int mpc8544_copy_soc_cell(void *fdt, const char *node, const char *prop) { @@ -82,7 +89,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, { int ret = -1; #ifdef CONFIG_FDT - uint32_t mem_reg_property[] = {0, ramsize}; + uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; char *filename; int fdt_size; void *fdt; @@ -103,15 +110,19 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, if (ret < 0) fprintf(stderr, "couldn't set /memory/reg\n"); - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", - initrd_base); - if (ret < 0) - fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + if (initrd_size) { + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_base); + if (ret < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + } - ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", - (initrd_base + initrd_size)); - if (ret < 0) - fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", + (initrd_base + initrd_size)); + if (ret < 0) { + fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + } + } ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); @@ -145,6 +156,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr, mpc8544_copy_soc_cell(fdt, buf, "clock-frequency"); mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency"); + } else { + const uint32_t freq = 400000000; + + qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0", + "clock-frequency", freq); + qemu_devtree_setprop_cell(fdt, "/cpus/PowerPC,8544@0", + "timebase-frequency", freq); } ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); @@ -156,6 +174,35 @@ out: return ret; } +/* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ +static void mmubooke_create_initial_mapping(CPUState *env, + target_ulong va, + target_phys_addr_t pa) +{ + ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0); + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 256 * 1024 * 1024; + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static void mpc8544ds_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + struct boot_info *bi = env->load_info; + + cpu_reset(env); + + /* Set initial guest state. */ + env->gpr[1] = (16<<20) - 8; + env->gpr[3] = bi->dt_base; + env->nip = bi->entry; + mmubooke_create_initial_mapping(env, 0, 0); +} + static void mpc8544ds_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -175,15 +222,28 @@ static void mpc8544ds_init(ram_addr_t ram_size, target_long initrd_size=0; int i=0; unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; - qemu_irq *irqs, *mpic, *pci_irqs; + qemu_irq *irqs, *mpic; + DeviceState *dev; + struct boot_info *boot_info; /* Setup CPU */ - env = cpu_ppc_init("e500v2_v30"); + if (cpu_model == NULL) { + cpu_model = "e500v2_v30"; + } + + env = cpu_ppc_init(cpu_model); if (!env) { fprintf(stderr, "Unable to initialize CPU!\n"); exit(1); } + /* XXX register timer? */ + ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR); + ppc_dcr_init(env, NULL, NULL); + + /* Register reset handler */ + qemu_register_reset(mpc8544ds_cpu_reset, env); + /* Fixup Memory size on a alignment boundary */ ram_size &= ~(RAM_SIZES_ALIGN - 1); @@ -211,12 +271,11 @@ static void mpc8544ds_init(ram_addr_t ram_size, } /* PCI */ - pci_irqs = qemu_malloc(sizeof(qemu_irq) * 4); - pci_irqs[0] = mpic[pci_irq_nrs[0]]; - pci_irqs[1] = mpic[pci_irq_nrs[1]]; - pci_irqs[2] = mpic[pci_irq_nrs[2]]; - pci_irqs[3] = mpic[pci_irq_nrs[3]]; - pci_bus = ppce500_pci_init(pci_irqs, MPC8544_PCI_REGS_BASE); + dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, + mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], + mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]], + NULL); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci"); if (!pci_bus) printf("couldn't create PCI controller!\n"); @@ -259,8 +318,13 @@ static void mpc8544ds_init(ram_addr_t ram_size, } } + boot_info = qemu_mallocz(sizeof(struct boot_info)); + /* If we're loading a kernel directly, we must load the device tree too. */ if (kernel_filename) { +#ifndef CONFIG_FDT + cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); +#endif dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; if (mpc8544_load_device_tree(dt_base, ram_size, initrd_base, initrd_size, kernel_cmdline) < 0) { @@ -268,17 +332,14 @@ static void mpc8544ds_init(ram_addr_t ram_size, exit(1); } - /* Set initial guest state. */ - env->gpr[1] = (16<<20) - 8; - env->gpr[3] = dt_base; - env->nip = entry; - /* XXX we currently depend on KVM to create some initial TLB entries. */ + boot_info->entry = entry; + boot_info->dt_base = dt_base; } + env->load_info = boot_info; - if (kvm_enabled()) + if (kvm_enabled()) { kvmppc_init(); - - return; + } } static QEMUMachine mpc8544ds_machine = { diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 83a20e4620..069af9691a 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -15,7 +15,6 @@ */ #include "hw.h" -#include "ppce500.h" #include "pci.h" #include "pci_host.h" #include "bswap.h" @@ -29,7 +28,8 @@ #define PCIE500_CFGADDR 0x0 #define PCIE500_CFGDATA 0x4 #define PCIE500_REG_BASE 0xC00 -#define PCIE500_REG_SIZE (0x1000 - PCIE500_REG_BASE) +#define PCIE500_ALL_SIZE 0x1000 +#define PCIE500_REG_SIZE (PCIE500_ALL_SIZE - PCIE500_REG_BASE) #define PPCE500_PCI_CONFIG_ADDR 0x0 #define PPCE500_PCI_CONFIG_DATA 0x4 @@ -73,11 +73,15 @@ struct pci_inbound { }; struct PPCE500PCIState { + PCIHostState pci_state; struct pci_outbound pob[PPCE500_PCI_NR_POBS]; struct pci_inbound pib[PPCE500_PCI_NR_PIBS]; uint32_t gasket_time; - PCIHostState pci_state; - PCIDevice *pci_dev; + qemu_irq irq[4]; + /* mmio maps */ + int cfgaddr; + int cfgdata; + int reg; }; typedef struct PPCE500PCIState PPCE500PCIState; @@ -250,7 +254,6 @@ static const VMStateDescription vmstate_ppce500_pci = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPCE500PCIState), VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1, vmstate_pci_outbound, struct pci_outbound), VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1, @@ -260,60 +263,73 @@ static const VMStateDescription vmstate_ppce500_pci = { } }; -PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers) +static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base) +{ + PCIHostState *h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); + PPCE500PCIState *s = DO_UPCAST(PPCE500PCIState, pci_state, h); + + cpu_register_physical_memory(base + PCIE500_CFGADDR, 4, s->cfgaddr); + cpu_register_physical_memory(base + PCIE500_CFGDATA, 4, s->cfgdata); + cpu_register_physical_memory(base + PCIE500_REG_BASE, PCIE500_REG_SIZE, + s->reg); +} + +static int e500_pcihost_initfn(SysBusDevice *dev) +{ + PCIHostState *h; + PPCE500PCIState *s; + PCIBus *b; + int i; + + h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); + s = DO_UPCAST(PPCE500PCIState, pci_state, h); + + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { + sysbus_init_irq(dev, &s->irq[i]); + } + + b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq, + mpc85xx_pci_map_irq, s->irq, PCI_DEVFN(0x11, 0), 4); + s->pci_state.bus = b; + + pci_create_simple(b, 0, "e500-host-bridge"); + + s->cfgaddr = pci_host_conf_register_mmio(&s->pci_state, DEVICE_BIG_ENDIAN); + s->cfgdata = pci_host_data_register_mmio(&s->pci_state, + DEVICE_LITTLE_ENDIAN); + s->reg = cpu_register_io_memory(e500_pci_reg_read, e500_pci_reg_write, s, + DEVICE_BIG_ENDIAN); + sysbus_init_mmio_cb(dev, PCIE500_ALL_SIZE, e500_pci_map); + + return 0; +} + +static int e500_host_bridge_initfn(PCIDevice *dev) +{ + pci_config_set_vendor_id(dev->config, PCI_VENDOR_ID_FREESCALE); + pci_config_set_device_id(dev->config, PCI_DEVICE_ID_MPC8533E); + pci_config_set_class(dev->config, PCI_CLASS_PROCESSOR_POWERPC); + + return 0; +} + +static PCIDeviceInfo e500_host_bridge_info = { + .qdev.name = "e500-host-bridge", + .qdev.desc = "Host bridge", + .qdev.size = sizeof(PCIDevice), + .init = e500_host_bridge_initfn, +}; + +static SysBusDeviceInfo e500_pcihost_info = { + .init = e500_pcihost_initfn, + .qdev.name = "e500-pcihost", + .qdev.size = sizeof(PPCE500PCIState), + .qdev.vmsd = &vmstate_ppce500_pci, +}; + +static void e500_pci_register(void) { - PPCE500PCIState *controller; - PCIDevice *d; - int index; - static int ppce500_pci_id; - - controller = qemu_mallocz(sizeof(PPCE500PCIState)); - - controller->pci_state.bus = pci_register_bus(NULL, "pci", - mpc85xx_pci_set_irq, - mpc85xx_pci_map_irq, - pci_irqs, PCI_DEVFN(0x11, 0), - 4); - d = pci_register_device(controller->pci_state.bus, - "host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - - pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_FREESCALE); - pci_config_set_device_id(d->config, PCI_DEVICE_ID_MPC8533E); - pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_POWERPC); - - controller->pci_dev = d; - - /* CFGADDR */ - index = pci_host_conf_register_mmio(&controller->pci_state, - DEVICE_BIG_ENDIAN); - if (index < 0) - goto free; - cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index); - - /* CFGDATA */ - index = pci_host_data_register_mmio(&controller->pci_state, - DEVICE_BIG_ENDIAN); - if (index < 0) - goto free; - cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index); - - index = cpu_register_io_memory(e500_pci_reg_read, - e500_pci_reg_write, controller, - DEVICE_NATIVE_ENDIAN); - if (index < 0) - goto free; - cpu_register_physical_memory(registers + PCIE500_REG_BASE, - PCIE500_REG_SIZE, index); - - /* XXX load/save code not tested. */ - vmstate_register(&d->qdev, ppce500_pci_id++, &vmstate_ppce500_pci, - controller); - - return controller->pci_state.bus; - -free: - printf("%s error\n", __func__); - qemu_free(controller); - return NULL; + sysbus_register_withprop(&e500_pcihost_info); + pci_qdev_register(&e500_host_bridge_info); } +device_init(e500_pci_register); diff --git a/hw/spapr.c b/hw/spapr.c index 1782cc0a94..109b77459a 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -51,7 +51,7 @@ #define TIMEBASE_FREQ 512000000ULL -#define MAX_CPUS 32 +#define MAX_CPUS 256 #define XICS_IRQS 1024 sPAPREnvironment *spapr; @@ -93,7 +93,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, /* Root node */ _FDT((fdt_begin_node(fdt, ""))); _FDT((fdt_property_string(fdt, "device_type", "chrp"))); - _FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR"))); + _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); @@ -362,8 +362,9 @@ static void ppc_spapr_init(ram_addr_t ram_size, for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) { if (serial_hds[i]) { - spapr_vty_create(spapr->vio_bus, i, serial_hds[i], - xics_find_qirq(spapr->icp, irq), irq); + spapr_vty_create(spapr->vio_bus, SPAPR_VTY_BASE_ADDRESS + i, + serial_hds[i], xics_find_qirq(spapr->icp, irq), + irq); } } diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c index f88e1d2083..5281ba2b38 100644 --- a/hw/spapr_hcall.c +++ b/hw/spapr_hcall.c @@ -455,8 +455,8 @@ static target_ulong h_rtas(CPUState *env, sPAPREnvironment *spapr, nret, rtas_r3 + 12 + 4*nargs); } -spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; -spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE]; +static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1]; +static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1]; void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) { diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 16b65422b6..00c8ce5a15 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -44,7 +44,8 @@ static void rtas_display_character(sPAPREnvironment *spapr, uint32_t nret, target_ulong rets) { uint8_t c = rtas_ld(args, 0); - VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, 0); + VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, + SPAPR_VTY_BASE_ADDRESS); if (!sdev) { rtas_st(rets, 0, -1); diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 841b04351a..603a8c43a3 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -32,6 +32,8 @@ enum VIOsPAPR_TCEAccess { SPAPR_TCE_RW = 3, }; +#define SPAPR_VTY_BASE_ADDRESS 0x30000000 + struct VIOsPAPRDevice; typedef struct VIOsPAPR_RTCE { |