153018216SPaolo Bonzini /* 253018216SPaolo Bonzini * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator 353018216SPaolo Bonzini * 453018216SPaolo Bonzini * Copyright (c) 2004-2007 Fabrice Bellard 553018216SPaolo Bonzini * Copyright (c) 2007 Jocelyn Mayer 653018216SPaolo Bonzini * Copyright (c) 2010 David Gibson, IBM Corporation. 753018216SPaolo Bonzini * 853018216SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 953018216SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 1053018216SPaolo Bonzini * in the Software without restriction, including without limitation the rights 1153018216SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1253018216SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1353018216SPaolo Bonzini * furnished to do so, subject to the following conditions: 1453018216SPaolo Bonzini * 1553018216SPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1653018216SPaolo Bonzini * all copies or substantial portions of the Software. 1753018216SPaolo Bonzini * 1853018216SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1953018216SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2053018216SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2153018216SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2253018216SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2353018216SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2453018216SPaolo Bonzini * THE SOFTWARE. 2553018216SPaolo Bonzini * 2653018216SPaolo Bonzini */ 2753018216SPaolo Bonzini #include "sysemu/sysemu.h" 28e35704baSEduardo Habkost #include "sysemu/numa.h" 2953018216SPaolo Bonzini #include "hw/hw.h" 3071461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h" 3153018216SPaolo Bonzini #include "elf.h" 3253018216SPaolo Bonzini #include "net/net.h" 33ad440b4aSAndrew Jones #include "sysemu/device_tree.h" 34fa1d36dfSMarkus Armbruster #include "sysemu/block-backend.h" 3553018216SPaolo Bonzini #include "sysemu/cpus.h" 3653018216SPaolo Bonzini #include "sysemu/kvm.h" 37c20d332aSBharata B Rao #include "sysemu/device_tree.h" 3853018216SPaolo Bonzini #include "kvm_ppc.h" 39ff14e817SDr. David Alan Gilbert #include "migration/migration.h" 404be21d56SDavid Gibson #include "mmu-hash64.h" 413794d548SAlexey Kardashevskiy #include "qom/cpu.h" 4253018216SPaolo Bonzini 4353018216SPaolo Bonzini #include "hw/boards.h" 440d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 4553018216SPaolo Bonzini #include "hw/loader.h" 4653018216SPaolo Bonzini 470d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h" 480d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h" 490d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h" 500d09e41aSPaolo Bonzini #include "hw/ppc/xics.h" 5153018216SPaolo Bonzini #include "hw/pci/msi.h" 5253018216SPaolo Bonzini 5353018216SPaolo Bonzini #include "hw/pci/pci.h" 5471461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h" 5571461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h" 5653018216SPaolo Bonzini 5753018216SPaolo Bonzini #include "exec/address-spaces.h" 5853018216SPaolo Bonzini #include "hw/usb.h" 5953018216SPaolo Bonzini #include "qemu/config-file.h" 60135a129aSAneesh Kumar K.V #include "qemu/error-report.h" 612a6593cbSAlexey Kardashevskiy #include "trace.h" 6234316482SAlexey Kardashevskiy #include "hw/nmi.h" 6353018216SPaolo Bonzini 6468a27b20SMichael S. Tsirkin #include "hw/compat.h" 65224245bfSDavid Gibson #include "qemu-common.h" 6668a27b20SMichael S. Tsirkin 6753018216SPaolo Bonzini #include <libfdt.h> 6853018216SPaolo Bonzini 6953018216SPaolo Bonzini /* SLOF memory layout: 7053018216SPaolo Bonzini * 7153018216SPaolo Bonzini * SLOF raw image loaded at 0, copies its romfs right below the flat 7253018216SPaolo Bonzini * device-tree, then position SLOF itself 31M below that 7353018216SPaolo Bonzini * 7453018216SPaolo Bonzini * So we set FW_OVERHEAD to 40MB which should account for all of that 7553018216SPaolo Bonzini * and more 7653018216SPaolo Bonzini * 7753018216SPaolo Bonzini * We load our kernel at 4M, leaving space for SLOF initial image 7853018216SPaolo Bonzini */ 7938b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE 0x100000 8053018216SPaolo Bonzini #define RTAS_MAX_SIZE 0x10000 81b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ 8253018216SPaolo Bonzini #define FW_MAX_SIZE 0x400000 8353018216SPaolo Bonzini #define FW_FILE_NAME "slof.bin" 8453018216SPaolo Bonzini #define FW_OVERHEAD 0x2800000 8553018216SPaolo Bonzini #define KERNEL_LOAD_ADDR FW_MAX_SIZE 8653018216SPaolo Bonzini 8753018216SPaolo Bonzini #define MIN_RMA_SLOF 128UL 8853018216SPaolo Bonzini 8953018216SPaolo Bonzini #define TIMEBASE_FREQ 512000000ULL 9053018216SPaolo Bonzini 9153018216SPaolo Bonzini #define PHANDLE_XICP 0x00001111 9253018216SPaolo Bonzini 9353018216SPaolo Bonzini #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) 9453018216SPaolo Bonzini 95c04d6cfaSAnthony Liguori static XICSState *try_create_xics(const char *type, int nr_servers, 9634f2af3dSMarkus Armbruster int nr_irqs, Error **errp) 97c04d6cfaSAnthony Liguori { 9834f2af3dSMarkus Armbruster Error *err = NULL; 99c04d6cfaSAnthony Liguori DeviceState *dev; 100c04d6cfaSAnthony Liguori 101c04d6cfaSAnthony Liguori dev = qdev_create(NULL, type); 102c04d6cfaSAnthony Liguori qdev_prop_set_uint32(dev, "nr_servers", nr_servers); 103c04d6cfaSAnthony Liguori qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs); 10434f2af3dSMarkus Armbruster object_property_set_bool(OBJECT(dev), true, "realized", &err); 10534f2af3dSMarkus Armbruster if (err) { 10634f2af3dSMarkus Armbruster error_propagate(errp, err); 10734f2af3dSMarkus Armbruster object_unparent(OBJECT(dev)); 108c04d6cfaSAnthony Liguori return NULL; 109c04d6cfaSAnthony Liguori } 1105a3d7b23SAlexey Kardashevskiy return XICS_COMMON(dev); 111c04d6cfaSAnthony Liguori } 112c04d6cfaSAnthony Liguori 113446f16a6SMarcel Apfelbaum static XICSState *xics_system_init(MachineState *machine, 114446f16a6SMarcel Apfelbaum int nr_servers, int nr_irqs) 115c04d6cfaSAnthony Liguori { 116c04d6cfaSAnthony Liguori XICSState *icp = NULL; 117c04d6cfaSAnthony Liguori 11811ad93f6SDavid Gibson if (kvm_enabled()) { 11934f2af3dSMarkus Armbruster Error *err = NULL; 12034f2af3dSMarkus Armbruster 121446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_allowed(machine)) { 12234f2af3dSMarkus Armbruster icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs, &err); 12311ad93f6SDavid Gibson } 124446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_required(machine) && !icp) { 12534f2af3dSMarkus Armbruster error_report("kernel_irqchip requested but unavailable: %s", 12634f2af3dSMarkus Armbruster error_get_pretty(err)); 12711ad93f6SDavid Gibson } 12811ad93f6SDavid Gibson } 12911ad93f6SDavid Gibson 13011ad93f6SDavid Gibson if (!icp) { 13134f2af3dSMarkus Armbruster icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs, &error_abort); 132c04d6cfaSAnthony Liguori } 133c04d6cfaSAnthony Liguori 134c04d6cfaSAnthony Liguori return icp; 135c04d6cfaSAnthony Liguori } 136c04d6cfaSAnthony Liguori 137833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu, 138833d4668SAlexey Kardashevskiy int smt_threads) 139833d4668SAlexey Kardashevskiy { 140833d4668SAlexey Kardashevskiy int i, ret = 0; 141833d4668SAlexey Kardashevskiy uint32_t servers_prop[smt_threads]; 142833d4668SAlexey Kardashevskiy uint32_t gservers_prop[smt_threads * 2]; 143833d4668SAlexey Kardashevskiy int index = ppc_get_vcpu_dt_id(cpu); 144833d4668SAlexey Kardashevskiy 1456d9412eaSAlexey Kardashevskiy if (cpu->cpu_version) { 1464bce526eSLaurent Dufour ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version); 1476d9412eaSAlexey Kardashevskiy if (ret < 0) { 1486d9412eaSAlexey Kardashevskiy return ret; 1496d9412eaSAlexey Kardashevskiy } 1506d9412eaSAlexey Kardashevskiy } 1516d9412eaSAlexey Kardashevskiy 152833d4668SAlexey Kardashevskiy /* Build interrupt servers and gservers properties */ 153833d4668SAlexey Kardashevskiy for (i = 0; i < smt_threads; i++) { 154833d4668SAlexey Kardashevskiy servers_prop[i] = cpu_to_be32(index + i); 155833d4668SAlexey Kardashevskiy /* Hack, direct the group queues back to cpu 0 */ 156833d4668SAlexey Kardashevskiy gservers_prop[i*2] = cpu_to_be32(index + i); 157833d4668SAlexey Kardashevskiy gservers_prop[i*2 + 1] = 0; 158833d4668SAlexey Kardashevskiy } 159833d4668SAlexey Kardashevskiy ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s", 160833d4668SAlexey Kardashevskiy servers_prop, sizeof(servers_prop)); 161833d4668SAlexey Kardashevskiy if (ret < 0) { 162833d4668SAlexey Kardashevskiy return ret; 163833d4668SAlexey Kardashevskiy } 164833d4668SAlexey Kardashevskiy ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s", 165833d4668SAlexey Kardashevskiy gservers_prop, sizeof(gservers_prop)); 166833d4668SAlexey Kardashevskiy 167833d4668SAlexey Kardashevskiy return ret; 168833d4668SAlexey Kardashevskiy } 169833d4668SAlexey Kardashevskiy 1700da6f3feSBharata B Rao static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs) 1710da6f3feSBharata B Rao { 1720da6f3feSBharata B Rao int ret = 0; 1730da6f3feSBharata B Rao PowerPCCPU *cpu = POWERPC_CPU(cs); 1740da6f3feSBharata B Rao int index = ppc_get_vcpu_dt_id(cpu); 1750da6f3feSBharata B Rao uint32_t associativity[] = {cpu_to_be32(0x5), 1760da6f3feSBharata B Rao cpu_to_be32(0x0), 1770da6f3feSBharata B Rao cpu_to_be32(0x0), 1780da6f3feSBharata B Rao cpu_to_be32(0x0), 1790da6f3feSBharata B Rao cpu_to_be32(cs->numa_node), 1800da6f3feSBharata B Rao cpu_to_be32(index)}; 1810da6f3feSBharata B Rao 1820da6f3feSBharata B Rao /* Advertise NUMA via ibm,associativity */ 1830da6f3feSBharata B Rao if (nb_numa_nodes > 1) { 1840da6f3feSBharata B Rao ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, 1850da6f3feSBharata B Rao sizeof(associativity)); 1860da6f3feSBharata B Rao } 1870da6f3feSBharata B Rao 1880da6f3feSBharata B Rao return ret; 1890da6f3feSBharata B Rao } 1900da6f3feSBharata B Rao 19128e02042SDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr) 19253018216SPaolo Bonzini { 19382677ed2SAlexey Kardashevskiy int ret = 0, offset, cpus_offset; 19482677ed2SAlexey Kardashevskiy CPUState *cs; 19553018216SPaolo Bonzini char cpu_model[32]; 19653018216SPaolo Bonzini int smt = kvmppc_smt_threads(); 19753018216SPaolo Bonzini uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; 19853018216SPaolo Bonzini 19982677ed2SAlexey Kardashevskiy CPU_FOREACH(cs) { 20082677ed2SAlexey Kardashevskiy PowerPCCPU *cpu = POWERPC_CPU(cs); 20182677ed2SAlexey Kardashevskiy DeviceClass *dc = DEVICE_GET_CLASS(cs); 20282677ed2SAlexey Kardashevskiy int index = ppc_get_vcpu_dt_id(cpu); 20353018216SPaolo Bonzini 2040f20ba62SAlexey Kardashevskiy if ((index % smt) != 0) { 20553018216SPaolo Bonzini continue; 20653018216SPaolo Bonzini } 20753018216SPaolo Bonzini 20882677ed2SAlexey Kardashevskiy snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index); 20953018216SPaolo Bonzini 21082677ed2SAlexey Kardashevskiy cpus_offset = fdt_path_offset(fdt, "/cpus"); 21182677ed2SAlexey Kardashevskiy if (cpus_offset < 0) { 21282677ed2SAlexey Kardashevskiy cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), 21382677ed2SAlexey Kardashevskiy "cpus"); 21482677ed2SAlexey Kardashevskiy if (cpus_offset < 0) { 21582677ed2SAlexey Kardashevskiy return cpus_offset; 21682677ed2SAlexey Kardashevskiy } 21782677ed2SAlexey Kardashevskiy } 21882677ed2SAlexey Kardashevskiy offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model); 21982677ed2SAlexey Kardashevskiy if (offset < 0) { 22082677ed2SAlexey Kardashevskiy offset = fdt_add_subnode(fdt, cpus_offset, cpu_model); 22153018216SPaolo Bonzini if (offset < 0) { 22253018216SPaolo Bonzini return offset; 22353018216SPaolo Bonzini } 22482677ed2SAlexey Kardashevskiy } 22553018216SPaolo Bonzini 2260da6f3feSBharata B Rao ret = fdt_setprop(fdt, offset, "ibm,pft-size", 2270da6f3feSBharata B Rao pft_size_prop, sizeof(pft_size_prop)); 22853018216SPaolo Bonzini if (ret < 0) { 22953018216SPaolo Bonzini return ret; 23053018216SPaolo Bonzini } 23153018216SPaolo Bonzini 2320da6f3feSBharata B Rao ret = spapr_fixup_cpu_numa_dt(fdt, offset, cs); 23353018216SPaolo Bonzini if (ret < 0) { 23453018216SPaolo Bonzini return ret; 23553018216SPaolo Bonzini } 236833d4668SAlexey Kardashevskiy 23782677ed2SAlexey Kardashevskiy ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, 2382a48d993SAlexey Kardashevskiy ppc_get_compat_smt_threads(cpu)); 239833d4668SAlexey Kardashevskiy if (ret < 0) { 240833d4668SAlexey Kardashevskiy return ret; 241833d4668SAlexey Kardashevskiy } 24253018216SPaolo Bonzini } 24353018216SPaolo Bonzini return ret; 24453018216SPaolo Bonzini } 24553018216SPaolo Bonzini 24653018216SPaolo Bonzini 24753018216SPaolo Bonzini static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, 24853018216SPaolo Bonzini size_t maxsize) 24953018216SPaolo Bonzini { 25053018216SPaolo Bonzini size_t maxcells = maxsize / sizeof(uint32_t); 25153018216SPaolo Bonzini int i, j, count; 25253018216SPaolo Bonzini uint32_t *p = prop; 25353018216SPaolo Bonzini 25453018216SPaolo Bonzini for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { 25553018216SPaolo Bonzini struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; 25653018216SPaolo Bonzini 25753018216SPaolo Bonzini if (!sps->page_shift) { 25853018216SPaolo Bonzini break; 25953018216SPaolo Bonzini } 26053018216SPaolo Bonzini for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { 26153018216SPaolo Bonzini if (sps->enc[count].page_shift == 0) { 26253018216SPaolo Bonzini break; 26353018216SPaolo Bonzini } 26453018216SPaolo Bonzini } 26553018216SPaolo Bonzini if ((p - prop) >= (maxcells - 3 - count * 2)) { 26653018216SPaolo Bonzini break; 26753018216SPaolo Bonzini } 26853018216SPaolo Bonzini *(p++) = cpu_to_be32(sps->page_shift); 26953018216SPaolo Bonzini *(p++) = cpu_to_be32(sps->slb_enc); 27053018216SPaolo Bonzini *(p++) = cpu_to_be32(count); 27153018216SPaolo Bonzini for (j = 0; j < count; j++) { 27253018216SPaolo Bonzini *(p++) = cpu_to_be32(sps->enc[j].page_shift); 27353018216SPaolo Bonzini *(p++) = cpu_to_be32(sps->enc[j].pte_enc); 27453018216SPaolo Bonzini } 27553018216SPaolo Bonzini } 27653018216SPaolo Bonzini 27753018216SPaolo Bonzini return (p - prop) * sizeof(uint32_t); 27853018216SPaolo Bonzini } 27953018216SPaolo Bonzini 280b082d65aSAlexey Kardashevskiy static hwaddr spapr_node0_size(void) 281b082d65aSAlexey Kardashevskiy { 282fb164994SDavid Gibson MachineState *machine = MACHINE(qdev_get_machine()); 283fb164994SDavid Gibson 284b082d65aSAlexey Kardashevskiy if (nb_numa_nodes) { 285b082d65aSAlexey Kardashevskiy int i; 286b082d65aSAlexey Kardashevskiy for (i = 0; i < nb_numa_nodes; ++i) { 287b082d65aSAlexey Kardashevskiy if (numa_info[i].node_mem) { 288fb164994SDavid Gibson return MIN(pow2floor(numa_info[i].node_mem), 289fb164994SDavid Gibson machine->ram_size); 290b082d65aSAlexey Kardashevskiy } 291b082d65aSAlexey Kardashevskiy } 292b082d65aSAlexey Kardashevskiy } 293fb164994SDavid Gibson return machine->ram_size; 294b082d65aSAlexey Kardashevskiy } 295b082d65aSAlexey Kardashevskiy 29653018216SPaolo Bonzini #define _FDT(exp) \ 29753018216SPaolo Bonzini do { \ 29853018216SPaolo Bonzini int ret = (exp); \ 29953018216SPaolo Bonzini if (ret < 0) { \ 30053018216SPaolo Bonzini fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ 30153018216SPaolo Bonzini #exp, fdt_strerror(ret)); \ 30253018216SPaolo Bonzini exit(1); \ 30353018216SPaolo Bonzini } \ 30453018216SPaolo Bonzini } while (0) 30553018216SPaolo Bonzini 306a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1) 307a1d59c0fSAlexey Kardashevskiy { 308a1d59c0fSAlexey Kardashevskiy g_string_append_len(s, s1, strlen(s1) + 1); 309a1d59c0fSAlexey Kardashevskiy } 31053018216SPaolo Bonzini 3113bbf37f2SAndreas Färber static void *spapr_create_fdt_skel(hwaddr initrd_base, 31253018216SPaolo Bonzini hwaddr initrd_size, 31353018216SPaolo Bonzini hwaddr kernel_size, 31416457e7fSBenjamin Herrenschmidt bool little_endian, 31553018216SPaolo Bonzini const char *kernel_cmdline, 31653018216SPaolo Bonzini uint32_t epow_irq) 31753018216SPaolo Bonzini { 31853018216SPaolo Bonzini void *fdt; 31953018216SPaolo Bonzini uint32_t start_prop = cpu_to_be32(initrd_base); 32053018216SPaolo Bonzini uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); 321a1d59c0fSAlexey Kardashevskiy GString *hypertas = g_string_sized_new(256); 322a1d59c0fSAlexey Kardashevskiy GString *qemu_hypertas = g_string_sized_new(256); 32353018216SPaolo Bonzini uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; 3249e734e3dSBharata B Rao uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(max_cpus)}; 32553018216SPaolo Bonzini unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; 326ef951443SNikunj A Dadhania char *buf; 32753018216SPaolo Bonzini 328a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-pft"); 329a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-term"); 330a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-dabr"); 331a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-interrupt"); 332a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-tce"); 333a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-vio"); 334a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-splpar"); 335a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-bulk"); 336a1d59c0fSAlexey Kardashevskiy add_str(hypertas, "hcall-set-mode"); 337a1d59c0fSAlexey Kardashevskiy add_str(qemu_hypertas, "hcall-memop1"); 338a1d59c0fSAlexey Kardashevskiy 33953018216SPaolo Bonzini fdt = g_malloc0(FDT_MAX_SIZE); 34053018216SPaolo Bonzini _FDT((fdt_create(fdt, FDT_MAX_SIZE))); 34153018216SPaolo Bonzini 34253018216SPaolo Bonzini if (kernel_size) { 34353018216SPaolo Bonzini _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size))); 34453018216SPaolo Bonzini } 34553018216SPaolo Bonzini if (initrd_size) { 34653018216SPaolo Bonzini _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size))); 34753018216SPaolo Bonzini } 34853018216SPaolo Bonzini _FDT((fdt_finish_reservemap(fdt))); 34953018216SPaolo Bonzini 35053018216SPaolo Bonzini /* Root node */ 35153018216SPaolo Bonzini _FDT((fdt_begin_node(fdt, ""))); 35253018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "device_type", "chrp"))); 35353018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)"))); 354fa388916SAnthony Liguori _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries"))); 35553018216SPaolo Bonzini 356ef951443SNikunj A Dadhania /* 357ef951443SNikunj A Dadhania * Add info to guest to indentify which host is it being run on 358ef951443SNikunj A Dadhania * and what is the uuid of the guest 359ef951443SNikunj A Dadhania */ 360ef951443SNikunj A Dadhania if (kvmppc_get_host_model(&buf)) { 361ef951443SNikunj A Dadhania _FDT((fdt_property_string(fdt, "host-model", buf))); 362ef951443SNikunj A Dadhania g_free(buf); 363ef951443SNikunj A Dadhania } 364ef951443SNikunj A Dadhania if (kvmppc_get_host_serial(&buf)) { 365ef951443SNikunj A Dadhania _FDT((fdt_property_string(fdt, "host-serial", buf))); 366ef951443SNikunj A Dadhania g_free(buf); 367ef951443SNikunj A Dadhania } 368ef951443SNikunj A Dadhania 369ef951443SNikunj A Dadhania buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], 370ef951443SNikunj A Dadhania qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], 371ef951443SNikunj A Dadhania qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], 372ef951443SNikunj A Dadhania qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], 373ef951443SNikunj A Dadhania qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], 374ef951443SNikunj A Dadhania qemu_uuid[14], qemu_uuid[15]); 375ef951443SNikunj A Dadhania 376ef951443SNikunj A Dadhania _FDT((fdt_property_string(fdt, "vm,uuid", buf))); 377ef951443SNikunj A Dadhania g_free(buf); 378ef951443SNikunj A Dadhania 3792c1aaa81SSam Bobroff if (qemu_get_vm_name()) { 3802c1aaa81SSam Bobroff _FDT((fdt_property_string(fdt, "ibm,partition-name", 3812c1aaa81SSam Bobroff qemu_get_vm_name()))); 3822c1aaa81SSam Bobroff } 3832c1aaa81SSam Bobroff 38453018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); 38553018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); 38653018216SPaolo Bonzini 38753018216SPaolo Bonzini /* /chosen */ 38853018216SPaolo Bonzini _FDT((fdt_begin_node(fdt, "chosen"))); 38953018216SPaolo Bonzini 39053018216SPaolo Bonzini /* Set Form1_affinity */ 39153018216SPaolo Bonzini _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5)))); 39253018216SPaolo Bonzini 39353018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); 39453018216SPaolo Bonzini _FDT((fdt_property(fdt, "linux,initrd-start", 39553018216SPaolo Bonzini &start_prop, sizeof(start_prop)))); 39653018216SPaolo Bonzini _FDT((fdt_property(fdt, "linux,initrd-end", 39753018216SPaolo Bonzini &end_prop, sizeof(end_prop)))); 39853018216SPaolo Bonzini if (kernel_size) { 39953018216SPaolo Bonzini uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), 40053018216SPaolo Bonzini cpu_to_be64(kernel_size) }; 40153018216SPaolo Bonzini 40253018216SPaolo Bonzini _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); 40316457e7fSBenjamin Herrenschmidt if (little_endian) { 40416457e7fSBenjamin Herrenschmidt _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0))); 40516457e7fSBenjamin Herrenschmidt } 40653018216SPaolo Bonzini } 407cc84c0f3SAvik Sil if (boot_menu) { 408cc84c0f3SAvik Sil _FDT((fdt_property_cell(fdt, "qemu,boot-menu", boot_menu))); 409cc84c0f3SAvik Sil } 41053018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width))); 41153018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height))); 41253018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth))); 41353018216SPaolo Bonzini 41453018216SPaolo Bonzini _FDT((fdt_end_node(fdt))); 41553018216SPaolo Bonzini 41653018216SPaolo Bonzini /* RTAS */ 41753018216SPaolo Bonzini _FDT((fdt_begin_node(fdt, "rtas"))); 41853018216SPaolo Bonzini 419da95324eSAlexey Kardashevskiy if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { 420da95324eSAlexey Kardashevskiy add_str(hypertas, "hcall-multi-tce"); 421da95324eSAlexey Kardashevskiy } 422a1d59c0fSAlexey Kardashevskiy _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas->str, 423a1d59c0fSAlexey Kardashevskiy hypertas->len))); 424a1d59c0fSAlexey Kardashevskiy g_string_free(hypertas, TRUE); 425a1d59c0fSAlexey Kardashevskiy _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas->str, 426a1d59c0fSAlexey Kardashevskiy qemu_hypertas->len))); 427a1d59c0fSAlexey Kardashevskiy g_string_free(qemu_hypertas, TRUE); 42853018216SPaolo Bonzini 42953018216SPaolo Bonzini _FDT((fdt_property(fdt, "ibm,associativity-reference-points", 43053018216SPaolo Bonzini refpoints, sizeof(refpoints)))); 43153018216SPaolo Bonzini 43253018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX))); 43379853e18STyrel Datwyler _FDT((fdt_property_cell(fdt, "rtas-event-scan-rate", 43479853e18STyrel Datwyler RTAS_EVENT_SCAN_RATE))); 43553018216SPaolo Bonzini 436a95f9922SSam Bobroff if (msi_supported) { 437a95f9922SSam Bobroff _FDT((fdt_property(fdt, "ibm,change-msix-capable", NULL, 0))); 438a95f9922SSam Bobroff } 439a95f9922SSam Bobroff 4402e14072fSNikunj A Dadhania /* 4419d632f5fSzhanghailiang * According to PAPR, rtas ibm,os-term does not guarantee a return 4422e14072fSNikunj A Dadhania * back to the guest cpu. 4432e14072fSNikunj A Dadhania * 4442e14072fSNikunj A Dadhania * While an additional ibm,extended-os-term property indicates that 4452e14072fSNikunj A Dadhania * rtas call return will always occur. Set this property. 4462e14072fSNikunj A Dadhania */ 4472e14072fSNikunj A Dadhania _FDT((fdt_property(fdt, "ibm,extended-os-term", NULL, 0))); 4482e14072fSNikunj A Dadhania 44953018216SPaolo Bonzini _FDT((fdt_end_node(fdt))); 45053018216SPaolo Bonzini 45153018216SPaolo Bonzini /* interrupt controller */ 45253018216SPaolo Bonzini _FDT((fdt_begin_node(fdt, "interrupt-controller"))); 45353018216SPaolo Bonzini 45453018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "device_type", 45553018216SPaolo Bonzini "PowerPC-External-Interrupt-Presentation"))); 45653018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"))); 45753018216SPaolo Bonzini _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); 45853018216SPaolo Bonzini _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges", 45953018216SPaolo Bonzini interrupt_server_ranges_prop, 46053018216SPaolo Bonzini sizeof(interrupt_server_ranges_prop)))); 46153018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2))); 46253018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP))); 46353018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP))); 46453018216SPaolo Bonzini 46553018216SPaolo Bonzini _FDT((fdt_end_node(fdt))); 46653018216SPaolo Bonzini 46753018216SPaolo Bonzini /* vdevice */ 46853018216SPaolo Bonzini _FDT((fdt_begin_node(fdt, "vdevice"))); 46953018216SPaolo Bonzini 47053018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "device_type", "vdevice"))); 47153018216SPaolo Bonzini _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice"))); 47253018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); 47353018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); 47453018216SPaolo Bonzini _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2))); 47553018216SPaolo Bonzini _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0))); 47653018216SPaolo Bonzini 47753018216SPaolo Bonzini _FDT((fdt_end_node(fdt))); 47853018216SPaolo Bonzini 47953018216SPaolo Bonzini /* event-sources */ 48053018216SPaolo Bonzini spapr_events_fdt_skel(fdt, epow_irq); 48153018216SPaolo Bonzini 482f7d69146SAlexander Graf /* /hypervisor node */ 483f7d69146SAlexander Graf if (kvm_enabled()) { 484f7d69146SAlexander Graf uint8_t hypercall[16]; 485f7d69146SAlexander Graf 486f7d69146SAlexander Graf /* indicate KVM hypercall interface */ 487f7d69146SAlexander Graf _FDT((fdt_begin_node(fdt, "hypervisor"))); 488f7d69146SAlexander Graf _FDT((fdt_property_string(fdt, "compatible", "linux,kvm"))); 489f7d69146SAlexander Graf if (kvmppc_has_cap_fixup_hcalls()) { 490f7d69146SAlexander Graf /* 491f7d69146SAlexander Graf * Older KVM versions with older guest kernels were broken with the 492f7d69146SAlexander Graf * magic page, don't allow the guest to map it. 493f7d69146SAlexander Graf */ 494f7d69146SAlexander Graf kvmppc_get_hypercall(first_cpu->env_ptr, hypercall, 495f7d69146SAlexander Graf sizeof(hypercall)); 496f7d69146SAlexander Graf _FDT((fdt_property(fdt, "hcall-instructions", hypercall, 497f7d69146SAlexander Graf sizeof(hypercall)))); 498f7d69146SAlexander Graf } 499f7d69146SAlexander Graf _FDT((fdt_end_node(fdt))); 500f7d69146SAlexander Graf } 501f7d69146SAlexander Graf 50253018216SPaolo Bonzini _FDT((fdt_end_node(fdt))); /* close root node */ 50353018216SPaolo Bonzini _FDT((fdt_finish(fdt))); 50453018216SPaolo Bonzini 50553018216SPaolo Bonzini return fdt; 50653018216SPaolo Bonzini } 50753018216SPaolo Bonzini 50803d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start, 50926a8c353SAlexey Kardashevskiy hwaddr size) 51026a8c353SAlexey Kardashevskiy { 51126a8c353SAlexey Kardashevskiy uint32_t associativity[] = { 51226a8c353SAlexey Kardashevskiy cpu_to_be32(0x4), /* length */ 51326a8c353SAlexey Kardashevskiy cpu_to_be32(0x0), cpu_to_be32(0x0), 514c3b4f589SAlexey Kardashevskiy cpu_to_be32(0x0), cpu_to_be32(nodeid) 51526a8c353SAlexey Kardashevskiy }; 51626a8c353SAlexey Kardashevskiy char mem_name[32]; 51726a8c353SAlexey Kardashevskiy uint64_t mem_reg_property[2]; 51826a8c353SAlexey Kardashevskiy int off; 51926a8c353SAlexey Kardashevskiy 52026a8c353SAlexey Kardashevskiy mem_reg_property[0] = cpu_to_be64(start); 52126a8c353SAlexey Kardashevskiy mem_reg_property[1] = cpu_to_be64(size); 52226a8c353SAlexey Kardashevskiy 52326a8c353SAlexey Kardashevskiy sprintf(mem_name, "memory@" TARGET_FMT_lx, start); 52426a8c353SAlexey Kardashevskiy off = fdt_add_subnode(fdt, 0, mem_name); 52526a8c353SAlexey Kardashevskiy _FDT(off); 52626a8c353SAlexey Kardashevskiy _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); 52726a8c353SAlexey Kardashevskiy _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, 52826a8c353SAlexey Kardashevskiy sizeof(mem_reg_property)))); 52926a8c353SAlexey Kardashevskiy _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, 53026a8c353SAlexey Kardashevskiy sizeof(associativity)))); 53103d196b7SBharata B Rao return off; 53226a8c353SAlexey Kardashevskiy } 53326a8c353SAlexey Kardashevskiy 53428e02042SDavid Gibson static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt) 53553018216SPaolo Bonzini { 536fb164994SDavid Gibson MachineState *machine = MACHINE(spapr); 5377db8a127SAlexey Kardashevskiy hwaddr mem_start, node_size; 5387db8a127SAlexey Kardashevskiy int i, nb_nodes = nb_numa_nodes; 5397db8a127SAlexey Kardashevskiy NodeInfo *nodes = numa_info; 5407db8a127SAlexey Kardashevskiy NodeInfo ramnode; 54153018216SPaolo Bonzini 5427db8a127SAlexey Kardashevskiy /* No NUMA nodes, assume there is just one node with whole RAM */ 5437db8a127SAlexey Kardashevskiy if (!nb_numa_nodes) { 5447db8a127SAlexey Kardashevskiy nb_nodes = 1; 545fb164994SDavid Gibson ramnode.node_mem = machine->ram_size; 5467db8a127SAlexey Kardashevskiy nodes = &ramnode; 5475fe269b1SPaul Mackerras } 54853018216SPaolo Bonzini 5497db8a127SAlexey Kardashevskiy for (i = 0, mem_start = 0; i < nb_nodes; ++i) { 5507db8a127SAlexey Kardashevskiy if (!nodes[i].node_mem) { 5517db8a127SAlexey Kardashevskiy continue; 55253018216SPaolo Bonzini } 553fb164994SDavid Gibson if (mem_start >= machine->ram_size) { 5545fe269b1SPaul Mackerras node_size = 0; 5555fe269b1SPaul Mackerras } else { 5567db8a127SAlexey Kardashevskiy node_size = nodes[i].node_mem; 557fb164994SDavid Gibson if (node_size > machine->ram_size - mem_start) { 558fb164994SDavid Gibson node_size = machine->ram_size - mem_start; 5595fe269b1SPaul Mackerras } 5605fe269b1SPaul Mackerras } 5617db8a127SAlexey Kardashevskiy if (!mem_start) { 5627db8a127SAlexey Kardashevskiy /* ppc_spapr_init() checks for rma_size <= node0_size already */ 5637db8a127SAlexey Kardashevskiy mem_start += spapr->rma_size; 5647db8a127SAlexey Kardashevskiy node_size -= spapr->rma_size; 5657db8a127SAlexey Kardashevskiy } 5666010818cSAlexey Kardashevskiy for ( ; node_size; ) { 5676010818cSAlexey Kardashevskiy hwaddr sizetmp = pow2floor(node_size); 5686010818cSAlexey Kardashevskiy 5696010818cSAlexey Kardashevskiy /* mem_start != 0 here */ 5706010818cSAlexey Kardashevskiy if (ctzl(mem_start) < ctzl(sizetmp)) { 5716010818cSAlexey Kardashevskiy sizetmp = 1ULL << ctzl(mem_start); 5726010818cSAlexey Kardashevskiy } 5736010818cSAlexey Kardashevskiy 5746010818cSAlexey Kardashevskiy spapr_populate_memory_node(fdt, i, mem_start, sizetmp); 5756010818cSAlexey Kardashevskiy node_size -= sizetmp; 5766010818cSAlexey Kardashevskiy mem_start += sizetmp; 5776010818cSAlexey Kardashevskiy } 57853018216SPaolo Bonzini } 57953018216SPaolo Bonzini 58053018216SPaolo Bonzini return 0; 58153018216SPaolo Bonzini } 58253018216SPaolo Bonzini 5830da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset, 5840da6f3feSBharata B Rao sPAPRMachineState *spapr) 5850da6f3feSBharata B Rao { 5860da6f3feSBharata B Rao PowerPCCPU *cpu = POWERPC_CPU(cs); 5870da6f3feSBharata B Rao CPUPPCState *env = &cpu->env; 5880da6f3feSBharata B Rao PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs); 5890da6f3feSBharata B Rao int index = ppc_get_vcpu_dt_id(cpu); 5900da6f3feSBharata B Rao uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40), 5910da6f3feSBharata B Rao 0xffffffff, 0xffffffff}; 5920da6f3feSBharata B Rao uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_FREQ; 5930da6f3feSBharata B Rao uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000; 5940da6f3feSBharata B Rao uint32_t page_sizes_prop[64]; 5950da6f3feSBharata B Rao size_t page_sizes_prop_size; 59622419c2aSDavid Gibson uint32_t vcpus_per_socket = smp_threads * smp_cores; 5970da6f3feSBharata B Rao uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; 5980da6f3feSBharata B Rao 5990da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "reg", index))); 6000da6f3feSBharata B Rao _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu"))); 6010da6f3feSBharata B Rao 6020da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR]))); 6030da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size", 6040da6f3feSBharata B Rao env->dcache_line_size))); 6050da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size", 6060da6f3feSBharata B Rao env->dcache_line_size))); 6070da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size", 6080da6f3feSBharata B Rao env->icache_line_size))); 6090da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size", 6100da6f3feSBharata B Rao env->icache_line_size))); 6110da6f3feSBharata B Rao 6120da6f3feSBharata B Rao if (pcc->l1_dcache_size) { 6130da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size", 6140da6f3feSBharata B Rao pcc->l1_dcache_size))); 6150da6f3feSBharata B Rao } else { 6160da6f3feSBharata B Rao fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n"); 6170da6f3feSBharata B Rao } 6180da6f3feSBharata B Rao if (pcc->l1_icache_size) { 6190da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size", 6200da6f3feSBharata B Rao pcc->l1_icache_size))); 6210da6f3feSBharata B Rao } else { 6220da6f3feSBharata B Rao fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n"); 6230da6f3feSBharata B Rao } 6240da6f3feSBharata B Rao 6250da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); 6260da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); 6270da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr))); 6280da6f3feSBharata B Rao _FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); 6290da6f3feSBharata B Rao _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); 6300da6f3feSBharata B Rao 6310da6f3feSBharata B Rao if (env->spr_cb[SPR_PURR].oea_read) { 6320da6f3feSBharata B Rao _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0))); 6330da6f3feSBharata B Rao } 6340da6f3feSBharata B Rao 6350da6f3feSBharata B Rao if (env->mmu_model & POWERPC_MMU_1TSEG) { 6360da6f3feSBharata B Rao _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", 6370da6f3feSBharata B Rao segs, sizeof(segs)))); 6380da6f3feSBharata B Rao } 6390da6f3feSBharata B Rao 6400da6f3feSBharata B Rao /* Advertise VMX/VSX (vector extensions) if available 6410da6f3feSBharata B Rao * 0 / no property == no vector extensions 6420da6f3feSBharata B Rao * 1 == VMX / Altivec available 6430da6f3feSBharata B Rao * 2 == VSX available */ 6440da6f3feSBharata B Rao if (env->insns_flags & PPC_ALTIVEC) { 6450da6f3feSBharata B Rao uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; 6460da6f3feSBharata B Rao 6470da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); 6480da6f3feSBharata B Rao } 6490da6f3feSBharata B Rao 6500da6f3feSBharata B Rao /* Advertise DFP (Decimal Floating Point) if available 6510da6f3feSBharata B Rao * 0 / no property == no DFP 6520da6f3feSBharata B Rao * 1 == DFP available */ 6530da6f3feSBharata B Rao if (env->insns_flags2 & PPC2_DFP) { 6540da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); 6550da6f3feSBharata B Rao } 6560da6f3feSBharata B Rao 6570da6f3feSBharata B Rao page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop, 6580da6f3feSBharata B Rao sizeof(page_sizes_prop)); 6590da6f3feSBharata B Rao if (page_sizes_prop_size) { 6600da6f3feSBharata B Rao _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes", 6610da6f3feSBharata B Rao page_sizes_prop, page_sizes_prop_size))); 6620da6f3feSBharata B Rao } 6630da6f3feSBharata B Rao 6640da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", 66522419c2aSDavid Gibson cs->cpu_index / vcpus_per_socket))); 6660da6f3feSBharata B Rao 6670da6f3feSBharata B Rao _FDT((fdt_setprop(fdt, offset, "ibm,pft-size", 6680da6f3feSBharata B Rao pft_size_prop, sizeof(pft_size_prop)))); 6690da6f3feSBharata B Rao 6700da6f3feSBharata B Rao _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs)); 6710da6f3feSBharata B Rao 6720da6f3feSBharata B Rao _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu, 6730da6f3feSBharata B Rao ppc_get_compat_smt_threads(cpu))); 6740da6f3feSBharata B Rao } 6750da6f3feSBharata B Rao 6760da6f3feSBharata B Rao static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) 6770da6f3feSBharata B Rao { 6780da6f3feSBharata B Rao CPUState *cs; 6790da6f3feSBharata B Rao int cpus_offset; 6800da6f3feSBharata B Rao char *nodename; 6810da6f3feSBharata B Rao int smt = kvmppc_smt_threads(); 6820da6f3feSBharata B Rao 6830da6f3feSBharata B Rao cpus_offset = fdt_add_subnode(fdt, 0, "cpus"); 6840da6f3feSBharata B Rao _FDT(cpus_offset); 6850da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1))); 6860da6f3feSBharata B Rao _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0))); 6870da6f3feSBharata B Rao 6880da6f3feSBharata B Rao /* 6890da6f3feSBharata B Rao * We walk the CPUs in reverse order to ensure that CPU DT nodes 6900da6f3feSBharata B Rao * created by fdt_add_subnode() end up in the right order in FDT 6910da6f3feSBharata B Rao * for the guest kernel the enumerate the CPUs correctly. 6920da6f3feSBharata B Rao */ 6930da6f3feSBharata B Rao CPU_FOREACH_REVERSE(cs) { 6940da6f3feSBharata B Rao PowerPCCPU *cpu = POWERPC_CPU(cs); 6950da6f3feSBharata B Rao int index = ppc_get_vcpu_dt_id(cpu); 6960da6f3feSBharata B Rao DeviceClass *dc = DEVICE_GET_CLASS(cs); 6970da6f3feSBharata B Rao int offset; 6980da6f3feSBharata B Rao 6990da6f3feSBharata B Rao if ((index % smt) != 0) { 7000da6f3feSBharata B Rao continue; 7010da6f3feSBharata B Rao } 7020da6f3feSBharata B Rao 7030da6f3feSBharata B Rao nodename = g_strdup_printf("%s@%x", dc->fw_name, index); 7040da6f3feSBharata B Rao offset = fdt_add_subnode(fdt, cpus_offset, nodename); 7050da6f3feSBharata B Rao g_free(nodename); 7060da6f3feSBharata B Rao _FDT(offset); 7070da6f3feSBharata B Rao spapr_populate_cpu_dt(cs, fdt, offset, spapr); 7080da6f3feSBharata B Rao } 7090da6f3feSBharata B Rao 7100da6f3feSBharata B Rao } 7110da6f3feSBharata B Rao 71203d196b7SBharata B Rao /* 71303d196b7SBharata B Rao * Adds ibm,dynamic-reconfiguration-memory node. 71403d196b7SBharata B Rao * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation 71503d196b7SBharata B Rao * of this device tree node. 71603d196b7SBharata B Rao */ 71703d196b7SBharata B Rao static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) 71803d196b7SBharata B Rao { 71903d196b7SBharata B Rao MachineState *machine = MACHINE(spapr); 72003d196b7SBharata B Rao int ret, i, offset; 72103d196b7SBharata B Rao uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE; 72203d196b7SBharata B Rao uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)}; 72303d196b7SBharata B Rao uint32_t nr_rma_lmbs = spapr->rma_size/lmb_size; 72403d196b7SBharata B Rao uint32_t nr_lmbs = machine->maxram_size/lmb_size - nr_rma_lmbs; 72503d196b7SBharata B Rao uint32_t nr_assigned_lmbs = machine->ram_size/lmb_size - nr_rma_lmbs; 72603d196b7SBharata B Rao uint32_t *int_buf, *cur_index, buf_len; 72703d196b7SBharata B Rao 72803d196b7SBharata B Rao /* Allocate enough buffer size to fit in ibm,dynamic-memory */ 72903d196b7SBharata B Rao buf_len = nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE * sizeof(uint32_t) + 73003d196b7SBharata B Rao sizeof(uint32_t); 73103d196b7SBharata B Rao cur_index = int_buf = g_malloc0(buf_len); 73203d196b7SBharata B Rao 73303d196b7SBharata B Rao offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory"); 73403d196b7SBharata B Rao 73503d196b7SBharata B Rao ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size, 73603d196b7SBharata B Rao sizeof(prop_lmb_size)); 73703d196b7SBharata B Rao if (ret < 0) { 73803d196b7SBharata B Rao goto out; 73903d196b7SBharata B Rao } 74003d196b7SBharata B Rao 74103d196b7SBharata B Rao ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff); 74203d196b7SBharata B Rao if (ret < 0) { 74303d196b7SBharata B Rao goto out; 74403d196b7SBharata B Rao } 74503d196b7SBharata B Rao 74603d196b7SBharata B Rao ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0); 74703d196b7SBharata B Rao if (ret < 0) { 74803d196b7SBharata B Rao goto out; 74903d196b7SBharata B Rao } 75003d196b7SBharata B Rao 75103d196b7SBharata B Rao /* ibm,dynamic-memory */ 75203d196b7SBharata B Rao int_buf[0] = cpu_to_be32(nr_lmbs); 75303d196b7SBharata B Rao cur_index++; 75403d196b7SBharata B Rao for (i = 0; i < nr_lmbs; i++) { 75503d196b7SBharata B Rao sPAPRDRConnector *drc; 75603d196b7SBharata B Rao sPAPRDRConnectorClass *drck; 75703d196b7SBharata B Rao uint64_t addr; 75803d196b7SBharata B Rao uint32_t *dynamic_memory = cur_index; 75903d196b7SBharata B Rao 76003d196b7SBharata B Rao if (i < nr_assigned_lmbs) { 76103d196b7SBharata B Rao addr = (i + nr_rma_lmbs) * lmb_size; 76203d196b7SBharata B Rao } else { 76303d196b7SBharata B Rao addr = (i - nr_assigned_lmbs) * lmb_size + 76403d196b7SBharata B Rao spapr->hotplug_memory.base; 76503d196b7SBharata B Rao } 76603d196b7SBharata B Rao drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, 76703d196b7SBharata B Rao addr/lmb_size); 76803d196b7SBharata B Rao g_assert(drc); 76903d196b7SBharata B Rao drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); 77003d196b7SBharata B Rao 77103d196b7SBharata B Rao dynamic_memory[0] = cpu_to_be32(addr >> 32); 77203d196b7SBharata B Rao dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); 77303d196b7SBharata B Rao dynamic_memory[2] = cpu_to_be32(drck->get_index(drc)); 77403d196b7SBharata B Rao dynamic_memory[3] = cpu_to_be32(0); /* reserved */ 77503d196b7SBharata B Rao dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL)); 77603d196b7SBharata B Rao if (addr < machine->ram_size || 77703d196b7SBharata B Rao memory_region_present(get_system_memory(), addr)) { 77803d196b7SBharata B Rao dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED); 77903d196b7SBharata B Rao } else { 78003d196b7SBharata B Rao dynamic_memory[5] = cpu_to_be32(0); 78103d196b7SBharata B Rao } 78203d196b7SBharata B Rao 78303d196b7SBharata B Rao cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE; 78403d196b7SBharata B Rao } 78503d196b7SBharata B Rao ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len); 78603d196b7SBharata B Rao if (ret < 0) { 78703d196b7SBharata B Rao goto out; 78803d196b7SBharata B Rao } 78903d196b7SBharata B Rao 79003d196b7SBharata B Rao /* ibm,associativity-lookup-arrays */ 79103d196b7SBharata B Rao cur_index = int_buf; 79203d196b7SBharata B Rao int_buf[0] = cpu_to_be32(nb_numa_nodes); 79303d196b7SBharata B Rao int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */ 79403d196b7SBharata B Rao cur_index += 2; 79503d196b7SBharata B Rao for (i = 0; i < nb_numa_nodes; i++) { 79603d196b7SBharata B Rao uint32_t associativity[] = { 79703d196b7SBharata B Rao cpu_to_be32(0x0), 79803d196b7SBharata B Rao cpu_to_be32(0x0), 79903d196b7SBharata B Rao cpu_to_be32(0x0), 80003d196b7SBharata B Rao cpu_to_be32(i) 80103d196b7SBharata B Rao }; 80203d196b7SBharata B Rao memcpy(cur_index, associativity, sizeof(associativity)); 80303d196b7SBharata B Rao cur_index += 4; 80403d196b7SBharata B Rao } 80503d196b7SBharata B Rao ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf, 80603d196b7SBharata B Rao (cur_index - int_buf) * sizeof(uint32_t)); 80703d196b7SBharata B Rao out: 80803d196b7SBharata B Rao g_free(int_buf); 80903d196b7SBharata B Rao return ret; 81003d196b7SBharata B Rao } 81103d196b7SBharata B Rao 81203d196b7SBharata B Rao int spapr_h_cas_compose_response(sPAPRMachineState *spapr, 81303d196b7SBharata B Rao target_ulong addr, target_ulong size, 81403d196b7SBharata B Rao bool cpu_update, bool memory_update) 81503d196b7SBharata B Rao { 81603d196b7SBharata B Rao void *fdt, *fdt_skel; 81703d196b7SBharata B Rao sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 }; 81803d196b7SBharata B Rao sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine()); 81903d196b7SBharata B Rao 82003d196b7SBharata B Rao size -= sizeof(hdr); 82103d196b7SBharata B Rao 82203d196b7SBharata B Rao /* Create sceleton */ 82303d196b7SBharata B Rao fdt_skel = g_malloc0(size); 82403d196b7SBharata B Rao _FDT((fdt_create(fdt_skel, size))); 82503d196b7SBharata B Rao _FDT((fdt_begin_node(fdt_skel, ""))); 82603d196b7SBharata B Rao _FDT((fdt_end_node(fdt_skel))); 82703d196b7SBharata B Rao _FDT((fdt_finish(fdt_skel))); 82803d196b7SBharata B Rao fdt = g_malloc0(size); 82903d196b7SBharata B Rao _FDT((fdt_open_into(fdt_skel, fdt, size))); 83003d196b7SBharata B Rao g_free(fdt_skel); 83103d196b7SBharata B Rao 83203d196b7SBharata B Rao /* Fixup cpu nodes */ 83303d196b7SBharata B Rao if (cpu_update) { 83403d196b7SBharata B Rao _FDT((spapr_fixup_cpu_dt(fdt, spapr))); 83503d196b7SBharata B Rao } 83603d196b7SBharata B Rao 83703d196b7SBharata B Rao /* Generate memory nodes or ibm,dynamic-reconfiguration-memory node */ 83803d196b7SBharata B Rao if (memory_update && smc->dr_lmb_enabled) { 83903d196b7SBharata B Rao _FDT((spapr_populate_drconf_memory(spapr, fdt))); 84003d196b7SBharata B Rao } else { 84103d196b7SBharata B Rao _FDT((spapr_populate_memory(spapr, fdt))); 84203d196b7SBharata B Rao } 84303d196b7SBharata B Rao 84403d196b7SBharata B Rao /* Pack resulting tree */ 84503d196b7SBharata B Rao _FDT((fdt_pack(fdt))); 84603d196b7SBharata B Rao 84703d196b7SBharata B Rao if (fdt_totalsize(fdt) + sizeof(hdr) > size) { 84803d196b7SBharata B Rao trace_spapr_cas_failed(size); 84903d196b7SBharata B Rao return -1; 85003d196b7SBharata B Rao } 85103d196b7SBharata B Rao 85203d196b7SBharata B Rao cpu_physical_memory_write(addr, &hdr, sizeof(hdr)); 85303d196b7SBharata B Rao cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt)); 85403d196b7SBharata B Rao trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); 85503d196b7SBharata B Rao g_free(fdt); 85603d196b7SBharata B Rao 85703d196b7SBharata B Rao return 0; 85803d196b7SBharata B Rao } 85903d196b7SBharata B Rao 86028e02042SDavid Gibson static void spapr_finalize_fdt(sPAPRMachineState *spapr, 86153018216SPaolo Bonzini hwaddr fdt_addr, 86253018216SPaolo Bonzini hwaddr rtas_addr, 86353018216SPaolo Bonzini hwaddr rtas_size) 86453018216SPaolo Bonzini { 8655b2128d2SAlexander Graf MachineState *machine = MACHINE(qdev_get_machine()); 866c20d332aSBharata B Rao sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); 8675b2128d2SAlexander Graf const char *boot_device = machine->boot_order; 86871461b0fSAlexey Kardashevskiy int ret, i; 86971461b0fSAlexey Kardashevskiy size_t cb = 0; 87071461b0fSAlexey Kardashevskiy char *bootlist; 87153018216SPaolo Bonzini void *fdt; 87253018216SPaolo Bonzini sPAPRPHBState *phb; 87353018216SPaolo Bonzini 87453018216SPaolo Bonzini fdt = g_malloc(FDT_MAX_SIZE); 87553018216SPaolo Bonzini 87653018216SPaolo Bonzini /* open out the base tree into a temp buffer for the final tweaks */ 87753018216SPaolo Bonzini _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); 87853018216SPaolo Bonzini 87903d196b7SBharata B Rao /* 88003d196b7SBharata B Rao * Add memory@0 node to represent RMA. Rest of the memory is either 88103d196b7SBharata B Rao * represented by memory nodes or ibm,dynamic-reconfiguration-memory 88203d196b7SBharata B Rao * node later during ibm,client-architecture-support call. 88303d196b7SBharata B Rao * 88403d196b7SBharata B Rao * If NUMA is configured, ensure that memory@0 ends up in the 88503d196b7SBharata B Rao * first memory-less node. 88603d196b7SBharata B Rao */ 88703d196b7SBharata B Rao if (nb_numa_nodes) { 88803d196b7SBharata B Rao for (i = 0; i < nb_numa_nodes; ++i) { 88903d196b7SBharata B Rao if (numa_info[i].node_mem) { 89003d196b7SBharata B Rao spapr_populate_memory_node(fdt, i, 0, spapr->rma_size); 89103d196b7SBharata B Rao break; 89203d196b7SBharata B Rao } 89303d196b7SBharata B Rao } 89403d196b7SBharata B Rao } else { 89503d196b7SBharata B Rao spapr_populate_memory_node(fdt, 0, 0, spapr->rma_size); 89653018216SPaolo Bonzini } 89753018216SPaolo Bonzini 89853018216SPaolo Bonzini ret = spapr_populate_vdevice(spapr->vio_bus, fdt); 89953018216SPaolo Bonzini if (ret < 0) { 90053018216SPaolo Bonzini fprintf(stderr, "couldn't setup vio devices in fdt\n"); 90153018216SPaolo Bonzini exit(1); 90253018216SPaolo Bonzini } 90353018216SPaolo Bonzini 90453018216SPaolo Bonzini QLIST_FOREACH(phb, &spapr->phbs, list) { 90553018216SPaolo Bonzini ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt); 90653018216SPaolo Bonzini } 90753018216SPaolo Bonzini 90853018216SPaolo Bonzini if (ret < 0) { 90953018216SPaolo Bonzini fprintf(stderr, "couldn't setup PCI devices in fdt\n"); 91053018216SPaolo Bonzini exit(1); 91153018216SPaolo Bonzini } 91253018216SPaolo Bonzini 91353018216SPaolo Bonzini /* RTAS */ 91453018216SPaolo Bonzini ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size); 91553018216SPaolo Bonzini if (ret < 0) { 91653018216SPaolo Bonzini fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); 91753018216SPaolo Bonzini } 91853018216SPaolo Bonzini 9190da6f3feSBharata B Rao /* cpus */ 9200da6f3feSBharata B Rao spapr_populate_cpus_dt_node(fdt, spapr); 92153018216SPaolo Bonzini 92271461b0fSAlexey Kardashevskiy bootlist = get_boot_devices_list(&cb, true); 92371461b0fSAlexey Kardashevskiy if (cb && bootlist) { 92471461b0fSAlexey Kardashevskiy int offset = fdt_path_offset(fdt, "/chosen"); 92571461b0fSAlexey Kardashevskiy if (offset < 0) { 92671461b0fSAlexey Kardashevskiy exit(1); 92771461b0fSAlexey Kardashevskiy } 92871461b0fSAlexey Kardashevskiy for (i = 0; i < cb; i++) { 92971461b0fSAlexey Kardashevskiy if (bootlist[i] == '\n') { 93071461b0fSAlexey Kardashevskiy bootlist[i] = ' '; 93171461b0fSAlexey Kardashevskiy } 93271461b0fSAlexey Kardashevskiy 93371461b0fSAlexey Kardashevskiy } 93471461b0fSAlexey Kardashevskiy ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist); 93571461b0fSAlexey Kardashevskiy } 93671461b0fSAlexey Kardashevskiy 9375b2128d2SAlexander Graf if (boot_device && strlen(boot_device)) { 9385b2128d2SAlexander Graf int offset = fdt_path_offset(fdt, "/chosen"); 9395b2128d2SAlexander Graf 9405b2128d2SAlexander Graf if (offset < 0) { 9415b2128d2SAlexander Graf exit(1); 9425b2128d2SAlexander Graf } 9435b2128d2SAlexander Graf fdt_setprop_string(fdt, offset, "qemu,boot-device", boot_device); 9445b2128d2SAlexander Graf } 9455b2128d2SAlexander Graf 94653018216SPaolo Bonzini if (!spapr->has_graphics) { 94753018216SPaolo Bonzini spapr_populate_chosen_stdout(fdt, spapr->vio_bus); 94853018216SPaolo Bonzini } 94953018216SPaolo Bonzini 950c20d332aSBharata B Rao if (smc->dr_lmb_enabled) { 951c20d332aSBharata B Rao _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB)); 952c20d332aSBharata B Rao } 953c20d332aSBharata B Rao 95453018216SPaolo Bonzini _FDT((fdt_pack(fdt))); 95553018216SPaolo Bonzini 95653018216SPaolo Bonzini if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { 957730fce59SThomas Huth error_report("FDT too big ! 0x%x bytes (max is 0x%x)", 95853018216SPaolo Bonzini fdt_totalsize(fdt), FDT_MAX_SIZE); 95953018216SPaolo Bonzini exit(1); 96053018216SPaolo Bonzini } 96153018216SPaolo Bonzini 962ad440b4aSAndrew Jones qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); 96353018216SPaolo Bonzini cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); 96453018216SPaolo Bonzini 965a21a7a70SGonglei g_free(bootlist); 96653018216SPaolo Bonzini g_free(fdt); 96753018216SPaolo Bonzini } 96853018216SPaolo Bonzini 96953018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr) 97053018216SPaolo Bonzini { 97153018216SPaolo Bonzini return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR; 97253018216SPaolo Bonzini } 97353018216SPaolo Bonzini 97453018216SPaolo Bonzini static void emulate_spapr_hypercall(PowerPCCPU *cpu) 97553018216SPaolo Bonzini { 97653018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 97753018216SPaolo Bonzini 97853018216SPaolo Bonzini if (msr_pr) { 97953018216SPaolo Bonzini hcall_dprintf("Hypercall made with MSR[PR]=1\n"); 98053018216SPaolo Bonzini env->gpr[3] = H_PRIVILEGE; 98153018216SPaolo Bonzini } else { 98253018216SPaolo Bonzini env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]); 98353018216SPaolo Bonzini } 98453018216SPaolo Bonzini } 98553018216SPaolo Bonzini 986e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) 987e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID) 988e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY) 989e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY)) 990e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY)) 991e6b8fd24SSamuel Mendoza-Jonas 99228e02042SDavid Gibson static void spapr_reset_htab(sPAPRMachineState *spapr) 99353018216SPaolo Bonzini { 99453018216SPaolo Bonzini long shift; 995e6b8fd24SSamuel Mendoza-Jonas int index; 99653018216SPaolo Bonzini 99753018216SPaolo Bonzini /* allocate hash page table. For now we always make this 16mb, 99853018216SPaolo Bonzini * later we should probably make it scale to the size of guest 99953018216SPaolo Bonzini * RAM */ 100053018216SPaolo Bonzini 100153018216SPaolo Bonzini shift = kvmppc_reset_htab(spapr->htab_shift); 100253018216SPaolo Bonzini 100353018216SPaolo Bonzini if (shift > 0) { 100453018216SPaolo Bonzini /* Kernel handles htab, we don't need to allocate one */ 100553018216SPaolo Bonzini spapr->htab_shift = shift; 10067c43bca0SAneesh Kumar K.V kvmppc_kern_htab = true; 100701a57972SSamuel Mendoza-Jonas 100801a57972SSamuel Mendoza-Jonas /* Tell readers to update their file descriptor */ 100901a57972SSamuel Mendoza-Jonas if (spapr->htab_fd >= 0) { 101001a57972SSamuel Mendoza-Jonas spapr->htab_fd_stale = true; 101101a57972SSamuel Mendoza-Jonas } 101253018216SPaolo Bonzini } else { 101353018216SPaolo Bonzini if (!spapr->htab) { 101453018216SPaolo Bonzini /* Allocate an htab if we don't yet have one */ 101553018216SPaolo Bonzini spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); 101653018216SPaolo Bonzini } 101753018216SPaolo Bonzini 101853018216SPaolo Bonzini /* And clear it */ 101953018216SPaolo Bonzini memset(spapr->htab, 0, HTAB_SIZE(spapr)); 1020e6b8fd24SSamuel Mendoza-Jonas 1021e6b8fd24SSamuel Mendoza-Jonas for (index = 0; index < HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; index++) { 1022e6b8fd24SSamuel Mendoza-Jonas DIRTY_HPTE(HPTE(spapr->htab, index)); 1023e6b8fd24SSamuel Mendoza-Jonas } 102453018216SPaolo Bonzini } 102553018216SPaolo Bonzini 102653018216SPaolo Bonzini /* Update the RMA size if necessary */ 102753018216SPaolo Bonzini if (spapr->vrma_adjust) { 1028b082d65aSAlexey Kardashevskiy spapr->rma_size = kvmppc_rma_size(spapr_node0_size(), 1029b082d65aSAlexey Kardashevskiy spapr->htab_shift); 103053018216SPaolo Bonzini } 103153018216SPaolo Bonzini } 103253018216SPaolo Bonzini 10339e3f9733SAlexander Graf static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque) 10349e3f9733SAlexander Graf { 10359e3f9733SAlexander Graf bool matched = false; 10369e3f9733SAlexander Graf 10379e3f9733SAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) { 10389e3f9733SAlexander Graf matched = true; 10399e3f9733SAlexander Graf } 10409e3f9733SAlexander Graf 10419e3f9733SAlexander Graf if (!matched) { 10429e3f9733SAlexander Graf error_report("Device %s is not supported by this machine yet.", 10439e3f9733SAlexander Graf qdev_fw_name(DEVICE(sbdev))); 10449e3f9733SAlexander Graf exit(1); 10459e3f9733SAlexander Graf } 10469e3f9733SAlexander Graf 10479e3f9733SAlexander Graf return 0; 10489e3f9733SAlexander Graf } 10499e3f9733SAlexander Graf 105001a57972SSamuel Mendoza-Jonas /* 105101a57972SSamuel Mendoza-Jonas * A guest reset will cause spapr->htab_fd to become stale if being used. 105201a57972SSamuel Mendoza-Jonas * Reopen the file descriptor to make sure the whole HTAB is properly read. 105301a57972SSamuel Mendoza-Jonas */ 105428e02042SDavid Gibson static int spapr_check_htab_fd(sPAPRMachineState *spapr) 105501a57972SSamuel Mendoza-Jonas { 105601a57972SSamuel Mendoza-Jonas int rc = 0; 105701a57972SSamuel Mendoza-Jonas 105801a57972SSamuel Mendoza-Jonas if (spapr->htab_fd_stale) { 105901a57972SSamuel Mendoza-Jonas close(spapr->htab_fd); 106001a57972SSamuel Mendoza-Jonas spapr->htab_fd = kvmppc_get_htab_fd(false); 106101a57972SSamuel Mendoza-Jonas if (spapr->htab_fd < 0) { 106201a57972SSamuel Mendoza-Jonas error_report("Unable to open fd for reading hash table from KVM: " 106301a57972SSamuel Mendoza-Jonas "%s", strerror(errno)); 106401a57972SSamuel Mendoza-Jonas rc = -1; 106501a57972SSamuel Mendoza-Jonas } 106601a57972SSamuel Mendoza-Jonas spapr->htab_fd_stale = false; 106701a57972SSamuel Mendoza-Jonas } 106801a57972SSamuel Mendoza-Jonas 106901a57972SSamuel Mendoza-Jonas return rc; 107001a57972SSamuel Mendoza-Jonas } 107101a57972SSamuel Mendoza-Jonas 107253018216SPaolo Bonzini static void ppc_spapr_reset(void) 107353018216SPaolo Bonzini { 107428e02042SDavid Gibson sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); 1075182735efSAndreas Färber PowerPCCPU *first_ppc_cpu; 1076b7d1f77aSBenjamin Herrenschmidt uint32_t rtas_limit; 1077259186a7SAndreas Färber 10789e3f9733SAlexander Graf /* Check for unknown sysbus devices */ 10799e3f9733SAlexander Graf foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); 10809e3f9733SAlexander Graf 108153018216SPaolo Bonzini /* Reset the hash table & recalc the RMA */ 108253018216SPaolo Bonzini spapr_reset_htab(spapr); 108353018216SPaolo Bonzini 108453018216SPaolo Bonzini qemu_devices_reset(); 108553018216SPaolo Bonzini 1086b7d1f77aSBenjamin Herrenschmidt /* 1087b7d1f77aSBenjamin Herrenschmidt * We place the device tree and RTAS just below either the top of the RMA, 1088b7d1f77aSBenjamin Herrenschmidt * or just below 2GB, whichever is lowere, so that it can be 1089b7d1f77aSBenjamin Herrenschmidt * processed with 32-bit real mode code if necessary 1090b7d1f77aSBenjamin Herrenschmidt */ 1091b7d1f77aSBenjamin Herrenschmidt rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR); 1092b7d1f77aSBenjamin Herrenschmidt spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; 1093b7d1f77aSBenjamin Herrenschmidt spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; 1094b7d1f77aSBenjamin Herrenschmidt 109553018216SPaolo Bonzini /* Load the fdt */ 109653018216SPaolo Bonzini spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, 109753018216SPaolo Bonzini spapr->rtas_size); 109853018216SPaolo Bonzini 1099b7d1f77aSBenjamin Herrenschmidt /* Copy RTAS over */ 1100b7d1f77aSBenjamin Herrenschmidt cpu_physical_memory_write(spapr->rtas_addr, spapr->rtas_blob, 1101b7d1f77aSBenjamin Herrenschmidt spapr->rtas_size); 1102b7d1f77aSBenjamin Herrenschmidt 110353018216SPaolo Bonzini /* Set up the entry state */ 1104182735efSAndreas Färber first_ppc_cpu = POWERPC_CPU(first_cpu); 1105182735efSAndreas Färber first_ppc_cpu->env.gpr[3] = spapr->fdt_addr; 1106182735efSAndreas Färber first_ppc_cpu->env.gpr[5] = 0; 1107182735efSAndreas Färber first_cpu->halted = 0; 11081b718907SDavid Gibson first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT; 110953018216SPaolo Bonzini 111053018216SPaolo Bonzini } 111153018216SPaolo Bonzini 111253018216SPaolo Bonzini static void spapr_cpu_reset(void *opaque) 111353018216SPaolo Bonzini { 111428e02042SDavid Gibson sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); 111553018216SPaolo Bonzini PowerPCCPU *cpu = opaque; 1116259186a7SAndreas Färber CPUState *cs = CPU(cpu); 111753018216SPaolo Bonzini CPUPPCState *env = &cpu->env; 111853018216SPaolo Bonzini 1119259186a7SAndreas Färber cpu_reset(cs); 112053018216SPaolo Bonzini 112153018216SPaolo Bonzini /* All CPUs start halted. CPU0 is unhalted from the machine level 112253018216SPaolo Bonzini * reset code and the rest are explicitly started up by the guest 112353018216SPaolo Bonzini * using an RTAS call */ 1124259186a7SAndreas Färber cs->halted = 1; 112553018216SPaolo Bonzini 112653018216SPaolo Bonzini env->spr[SPR_HIOR] = 0; 112753018216SPaolo Bonzini 11284be21d56SDavid Gibson env->external_htab = (uint8_t *)spapr->htab; 11295736245cSAneesh Kumar K.V if (kvm_enabled() && !env->external_htab) { 11305736245cSAneesh Kumar K.V /* 11315736245cSAneesh Kumar K.V * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte* 11325736245cSAneesh Kumar K.V * functions do the right thing. 11335736245cSAneesh Kumar K.V */ 11345736245cSAneesh Kumar K.V env->external_htab = (void *)1; 11355736245cSAneesh Kumar K.V } 113653018216SPaolo Bonzini env->htab_base = -1; 1137f3c75d42SAneesh Kumar K.V /* 1138f3c75d42SAneesh Kumar K.V * htab_mask is the mask used to normalize hash value to PTEG index. 1139f3c75d42SAneesh Kumar K.V * htab_shift is log2 of hash table size. 1140f3c75d42SAneesh Kumar K.V * We have 8 hpte per group, and each hpte is 16 bytes. 1141f3c75d42SAneesh Kumar K.V * ie have 128 bytes per hpte entry. 1142f3c75d42SAneesh Kumar K.V */ 114328e02042SDavid Gibson env->htab_mask = (1ULL << (spapr->htab_shift - 7)) - 1; 1144ec4936e1SStefan Weil env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | 114553018216SPaolo Bonzini (spapr->htab_shift - 18); 114653018216SPaolo Bonzini } 114753018216SPaolo Bonzini 114828e02042SDavid Gibson static void spapr_create_nvram(sPAPRMachineState *spapr) 114953018216SPaolo Bonzini { 11502ff3de68SMarkus Armbruster DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram"); 11513978b863SPaolo Bonzini DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0); 115253018216SPaolo Bonzini 11533978b863SPaolo Bonzini if (dinfo) { 11544be74634SMarkus Armbruster qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(dinfo)); 115553018216SPaolo Bonzini } 115653018216SPaolo Bonzini 115753018216SPaolo Bonzini qdev_init_nofail(dev); 115853018216SPaolo Bonzini 115953018216SPaolo Bonzini spapr->nvram = (struct sPAPRNVRAM *)dev; 116053018216SPaolo Bonzini } 116153018216SPaolo Bonzini 116228e02042SDavid Gibson static void spapr_rtc_create(sPAPRMachineState *spapr) 116328df36a1SDavid Gibson { 116428df36a1SDavid Gibson DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC); 116528df36a1SDavid Gibson 116628df36a1SDavid Gibson qdev_init_nofail(dev); 116728df36a1SDavid Gibson spapr->rtc = dev; 116874e5ae28SDavid Gibson 116974e5ae28SDavid Gibson object_property_add_alias(qdev_get_machine(), "rtc-time", 117074e5ae28SDavid Gibson OBJECT(spapr->rtc), "date", NULL); 117128df36a1SDavid Gibson } 117228df36a1SDavid Gibson 117353018216SPaolo Bonzini /* Returns whether we want to use VGA or not */ 117453018216SPaolo Bonzini static int spapr_vga_init(PCIBus *pci_bus) 117553018216SPaolo Bonzini { 117653018216SPaolo Bonzini switch (vga_interface_type) { 117753018216SPaolo Bonzini case VGA_NONE: 11787effdaa3SMark Wu return false; 11797effdaa3SMark Wu case VGA_DEVICE: 11807effdaa3SMark Wu return true; 118153018216SPaolo Bonzini case VGA_STD: 118253018216SPaolo Bonzini return pci_vga_init(pci_bus) != NULL; 118353018216SPaolo Bonzini default: 118453018216SPaolo Bonzini fprintf(stderr, "This vga model is not supported," 118553018216SPaolo Bonzini "currently it only supports -vga std\n"); 118653018216SPaolo Bonzini exit(0); 118753018216SPaolo Bonzini } 118853018216SPaolo Bonzini } 118953018216SPaolo Bonzini 1190880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id) 1191880ae7deSDavid Gibson { 119228e02042SDavid Gibson sPAPRMachineState *spapr = (sPAPRMachineState *)opaque; 1193880ae7deSDavid Gibson int err = 0; 1194880ae7deSDavid Gibson 1195631b22eaSStefan Weil /* In earlier versions, there was no separate qdev for the PAPR 1196880ae7deSDavid Gibson * RTC, so the RTC offset was stored directly in sPAPREnvironment. 1197880ae7deSDavid Gibson * So when migrating from those versions, poke the incoming offset 1198880ae7deSDavid Gibson * value into the RTC device */ 1199880ae7deSDavid Gibson if (version_id < 3) { 1200880ae7deSDavid Gibson err = spapr_rtc_import_offset(spapr->rtc, spapr->rtc_offset); 1201880ae7deSDavid Gibson } 1202880ae7deSDavid Gibson 1203880ae7deSDavid Gibson return err; 1204880ae7deSDavid Gibson } 1205880ae7deSDavid Gibson 1206880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id) 1207880ae7deSDavid Gibson { 1208880ae7deSDavid Gibson return version_id < 3; 1209880ae7deSDavid Gibson } 1210880ae7deSDavid Gibson 12114be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = { 12124be21d56SDavid Gibson .name = "spapr", 1213880ae7deSDavid Gibson .version_id = 3, 12144be21d56SDavid Gibson .minimum_version_id = 1, 1215880ae7deSDavid Gibson .post_load = spapr_post_load, 12164be21d56SDavid Gibson .fields = (VMStateField[]) { 1217880ae7deSDavid Gibson /* used to be @next_irq */ 1218880ae7deSDavid Gibson VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4), 12194be21d56SDavid Gibson 12204be21d56SDavid Gibson /* RTC offset */ 122128e02042SDavid Gibson VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3), 1222880ae7deSDavid Gibson 122328e02042SDavid Gibson VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2), 12244be21d56SDavid Gibson VMSTATE_END_OF_LIST() 12254be21d56SDavid Gibson }, 12264be21d56SDavid Gibson }; 12274be21d56SDavid Gibson 12284be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque) 12294be21d56SDavid Gibson { 123028e02042SDavid Gibson sPAPRMachineState *spapr = opaque; 12314be21d56SDavid Gibson 12324be21d56SDavid Gibson /* "Iteration" header */ 12334be21d56SDavid Gibson qemu_put_be32(f, spapr->htab_shift); 12344be21d56SDavid Gibson 1235e68cb8b4SAlexey Kardashevskiy if (spapr->htab) { 1236e68cb8b4SAlexey Kardashevskiy spapr->htab_save_index = 0; 1237e68cb8b4SAlexey Kardashevskiy spapr->htab_first_pass = true; 1238e68cb8b4SAlexey Kardashevskiy } else { 1239e68cb8b4SAlexey Kardashevskiy assert(kvm_enabled()); 1240e68cb8b4SAlexey Kardashevskiy 1241e68cb8b4SAlexey Kardashevskiy spapr->htab_fd = kvmppc_get_htab_fd(false); 124201a57972SSamuel Mendoza-Jonas spapr->htab_fd_stale = false; 1243e68cb8b4SAlexey Kardashevskiy if (spapr->htab_fd < 0) { 1244e68cb8b4SAlexey Kardashevskiy fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", 1245e68cb8b4SAlexey Kardashevskiy strerror(errno)); 1246e68cb8b4SAlexey Kardashevskiy return -1; 1247e68cb8b4SAlexey Kardashevskiy } 12484be21d56SDavid Gibson } 12494be21d56SDavid Gibson 1250e68cb8b4SAlexey Kardashevskiy 1251e68cb8b4SAlexey Kardashevskiy return 0; 1252e68cb8b4SAlexey Kardashevskiy } 12534be21d56SDavid Gibson 125428e02042SDavid Gibson static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr, 12554be21d56SDavid Gibson int64_t max_ns) 12564be21d56SDavid Gibson { 12574be21d56SDavid Gibson int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; 12584be21d56SDavid Gibson int index = spapr->htab_save_index; 1259bc72ad67SAlex Bligh int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); 12604be21d56SDavid Gibson 12614be21d56SDavid Gibson assert(spapr->htab_first_pass); 12624be21d56SDavid Gibson 12634be21d56SDavid Gibson do { 12644be21d56SDavid Gibson int chunkstart; 12654be21d56SDavid Gibson 12664be21d56SDavid Gibson /* Consume invalid HPTEs */ 12674be21d56SDavid Gibson while ((index < htabslots) 12684be21d56SDavid Gibson && !HPTE_VALID(HPTE(spapr->htab, index))) { 12694be21d56SDavid Gibson index++; 12704be21d56SDavid Gibson CLEAN_HPTE(HPTE(spapr->htab, index)); 12714be21d56SDavid Gibson } 12724be21d56SDavid Gibson 12734be21d56SDavid Gibson /* Consume valid HPTEs */ 12744be21d56SDavid Gibson chunkstart = index; 1275338c25b6SSamuel Mendoza-Jonas while ((index < htabslots) && (index - chunkstart < USHRT_MAX) 12764be21d56SDavid Gibson && HPTE_VALID(HPTE(spapr->htab, index))) { 12774be21d56SDavid Gibson index++; 12784be21d56SDavid Gibson CLEAN_HPTE(HPTE(spapr->htab, index)); 12794be21d56SDavid Gibson } 12804be21d56SDavid Gibson 12814be21d56SDavid Gibson if (index > chunkstart) { 12824be21d56SDavid Gibson int n_valid = index - chunkstart; 12834be21d56SDavid Gibson 12844be21d56SDavid Gibson qemu_put_be32(f, chunkstart); 12854be21d56SDavid Gibson qemu_put_be16(f, n_valid); 12864be21d56SDavid Gibson qemu_put_be16(f, 0); 12874be21d56SDavid Gibson qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), 12884be21d56SDavid Gibson HASH_PTE_SIZE_64 * n_valid); 12894be21d56SDavid Gibson 1290bc72ad67SAlex Bligh if ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { 12914be21d56SDavid Gibson break; 12924be21d56SDavid Gibson } 12934be21d56SDavid Gibson } 12944be21d56SDavid Gibson } while ((index < htabslots) && !qemu_file_rate_limit(f)); 12954be21d56SDavid Gibson 12964be21d56SDavid Gibson if (index >= htabslots) { 12974be21d56SDavid Gibson assert(index == htabslots); 12984be21d56SDavid Gibson index = 0; 12994be21d56SDavid Gibson spapr->htab_first_pass = false; 13004be21d56SDavid Gibson } 13014be21d56SDavid Gibson spapr->htab_save_index = index; 13024be21d56SDavid Gibson } 13034be21d56SDavid Gibson 130428e02042SDavid Gibson static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr, 13054be21d56SDavid Gibson int64_t max_ns) 13064be21d56SDavid Gibson { 13074be21d56SDavid Gibson bool final = max_ns < 0; 13084be21d56SDavid Gibson int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; 13094be21d56SDavid Gibson int examined = 0, sent = 0; 13104be21d56SDavid Gibson int index = spapr->htab_save_index; 1311bc72ad67SAlex Bligh int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); 13124be21d56SDavid Gibson 13134be21d56SDavid Gibson assert(!spapr->htab_first_pass); 13144be21d56SDavid Gibson 13154be21d56SDavid Gibson do { 13164be21d56SDavid Gibson int chunkstart, invalidstart; 13174be21d56SDavid Gibson 13184be21d56SDavid Gibson /* Consume non-dirty HPTEs */ 13194be21d56SDavid Gibson while ((index < htabslots) 13204be21d56SDavid Gibson && !HPTE_DIRTY(HPTE(spapr->htab, index))) { 13214be21d56SDavid Gibson index++; 13224be21d56SDavid Gibson examined++; 13234be21d56SDavid Gibson } 13244be21d56SDavid Gibson 13254be21d56SDavid Gibson chunkstart = index; 13264be21d56SDavid Gibson /* Consume valid dirty HPTEs */ 1327338c25b6SSamuel Mendoza-Jonas while ((index < htabslots) && (index - chunkstart < USHRT_MAX) 13284be21d56SDavid Gibson && HPTE_DIRTY(HPTE(spapr->htab, index)) 13294be21d56SDavid Gibson && HPTE_VALID(HPTE(spapr->htab, index))) { 13304be21d56SDavid Gibson CLEAN_HPTE(HPTE(spapr->htab, index)); 13314be21d56SDavid Gibson index++; 13324be21d56SDavid Gibson examined++; 13334be21d56SDavid Gibson } 13344be21d56SDavid Gibson 13354be21d56SDavid Gibson invalidstart = index; 13364be21d56SDavid Gibson /* Consume invalid dirty HPTEs */ 1337338c25b6SSamuel Mendoza-Jonas while ((index < htabslots) && (index - invalidstart < USHRT_MAX) 13384be21d56SDavid Gibson && HPTE_DIRTY(HPTE(spapr->htab, index)) 13394be21d56SDavid Gibson && !HPTE_VALID(HPTE(spapr->htab, index))) { 13404be21d56SDavid Gibson CLEAN_HPTE(HPTE(spapr->htab, index)); 13414be21d56SDavid Gibson index++; 13424be21d56SDavid Gibson examined++; 13434be21d56SDavid Gibson } 13444be21d56SDavid Gibson 13454be21d56SDavid Gibson if (index > chunkstart) { 13464be21d56SDavid Gibson int n_valid = invalidstart - chunkstart; 13474be21d56SDavid Gibson int n_invalid = index - invalidstart; 13484be21d56SDavid Gibson 13494be21d56SDavid Gibson qemu_put_be32(f, chunkstart); 13504be21d56SDavid Gibson qemu_put_be16(f, n_valid); 13514be21d56SDavid Gibson qemu_put_be16(f, n_invalid); 13524be21d56SDavid Gibson qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), 13534be21d56SDavid Gibson HASH_PTE_SIZE_64 * n_valid); 13544be21d56SDavid Gibson sent += index - chunkstart; 13554be21d56SDavid Gibson 1356bc72ad67SAlex Bligh if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { 13574be21d56SDavid Gibson break; 13584be21d56SDavid Gibson } 13594be21d56SDavid Gibson } 13604be21d56SDavid Gibson 13614be21d56SDavid Gibson if (examined >= htabslots) { 13624be21d56SDavid Gibson break; 13634be21d56SDavid Gibson } 13644be21d56SDavid Gibson 13654be21d56SDavid Gibson if (index >= htabslots) { 13664be21d56SDavid Gibson assert(index == htabslots); 13674be21d56SDavid Gibson index = 0; 13684be21d56SDavid Gibson } 13694be21d56SDavid Gibson } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final)); 13704be21d56SDavid Gibson 13714be21d56SDavid Gibson if (index >= htabslots) { 13724be21d56SDavid Gibson assert(index == htabslots); 13734be21d56SDavid Gibson index = 0; 13744be21d56SDavid Gibson } 13754be21d56SDavid Gibson 13764be21d56SDavid Gibson spapr->htab_save_index = index; 13774be21d56SDavid Gibson 1378e68cb8b4SAlexey Kardashevskiy return (examined >= htabslots) && (sent == 0) ? 1 : 0; 13794be21d56SDavid Gibson } 13804be21d56SDavid Gibson 1381e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS 5000000 /* 5 ms */ 1382e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE 2048 1383e68cb8b4SAlexey Kardashevskiy 13844be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque) 13854be21d56SDavid Gibson { 138628e02042SDavid Gibson sPAPRMachineState *spapr = opaque; 1387e68cb8b4SAlexey Kardashevskiy int rc = 0; 13884be21d56SDavid Gibson 13894be21d56SDavid Gibson /* Iteration header */ 13904be21d56SDavid Gibson qemu_put_be32(f, 0); 13914be21d56SDavid Gibson 1392e68cb8b4SAlexey Kardashevskiy if (!spapr->htab) { 1393e68cb8b4SAlexey Kardashevskiy assert(kvm_enabled()); 1394e68cb8b4SAlexey Kardashevskiy 139501a57972SSamuel Mendoza-Jonas rc = spapr_check_htab_fd(spapr); 139601a57972SSamuel Mendoza-Jonas if (rc < 0) { 139701a57972SSamuel Mendoza-Jonas return rc; 139801a57972SSamuel Mendoza-Jonas } 139901a57972SSamuel Mendoza-Jonas 1400e68cb8b4SAlexey Kardashevskiy rc = kvmppc_save_htab(f, spapr->htab_fd, 1401e68cb8b4SAlexey Kardashevskiy MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); 1402e68cb8b4SAlexey Kardashevskiy if (rc < 0) { 1403e68cb8b4SAlexey Kardashevskiy return rc; 1404e68cb8b4SAlexey Kardashevskiy } 1405e68cb8b4SAlexey Kardashevskiy } else if (spapr->htab_first_pass) { 14064be21d56SDavid Gibson htab_save_first_pass(f, spapr, MAX_ITERATION_NS); 14074be21d56SDavid Gibson } else { 1408e68cb8b4SAlexey Kardashevskiy rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); 14094be21d56SDavid Gibson } 14104be21d56SDavid Gibson 14114be21d56SDavid Gibson /* End marker */ 14124be21d56SDavid Gibson qemu_put_be32(f, 0); 14134be21d56SDavid Gibson qemu_put_be16(f, 0); 14144be21d56SDavid Gibson qemu_put_be16(f, 0); 14154be21d56SDavid Gibson 1416e68cb8b4SAlexey Kardashevskiy return rc; 14174be21d56SDavid Gibson } 14184be21d56SDavid Gibson 14194be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque) 14204be21d56SDavid Gibson { 142128e02042SDavid Gibson sPAPRMachineState *spapr = opaque; 14224be21d56SDavid Gibson 14234be21d56SDavid Gibson /* Iteration header */ 14244be21d56SDavid Gibson qemu_put_be32(f, 0); 14254be21d56SDavid Gibson 1426e68cb8b4SAlexey Kardashevskiy if (!spapr->htab) { 1427e68cb8b4SAlexey Kardashevskiy int rc; 1428e68cb8b4SAlexey Kardashevskiy 1429e68cb8b4SAlexey Kardashevskiy assert(kvm_enabled()); 1430e68cb8b4SAlexey Kardashevskiy 143101a57972SSamuel Mendoza-Jonas rc = spapr_check_htab_fd(spapr); 143201a57972SSamuel Mendoza-Jonas if (rc < 0) { 143301a57972SSamuel Mendoza-Jonas return rc; 143401a57972SSamuel Mendoza-Jonas } 143501a57972SSamuel Mendoza-Jonas 1436e68cb8b4SAlexey Kardashevskiy rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); 1437e68cb8b4SAlexey Kardashevskiy if (rc < 0) { 1438e68cb8b4SAlexey Kardashevskiy return rc; 1439e68cb8b4SAlexey Kardashevskiy } 1440e68cb8b4SAlexey Kardashevskiy close(spapr->htab_fd); 1441e68cb8b4SAlexey Kardashevskiy spapr->htab_fd = -1; 1442e68cb8b4SAlexey Kardashevskiy } else { 14434be21d56SDavid Gibson htab_save_later_pass(f, spapr, -1); 1444e68cb8b4SAlexey Kardashevskiy } 14454be21d56SDavid Gibson 14464be21d56SDavid Gibson /* End marker */ 14474be21d56SDavid Gibson qemu_put_be32(f, 0); 14484be21d56SDavid Gibson qemu_put_be16(f, 0); 14494be21d56SDavid Gibson qemu_put_be16(f, 0); 14504be21d56SDavid Gibson 14514be21d56SDavid Gibson return 0; 14524be21d56SDavid Gibson } 14534be21d56SDavid Gibson 14544be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id) 14554be21d56SDavid Gibson { 145628e02042SDavid Gibson sPAPRMachineState *spapr = opaque; 14574be21d56SDavid Gibson uint32_t section_hdr; 1458e68cb8b4SAlexey Kardashevskiy int fd = -1; 14594be21d56SDavid Gibson 14604be21d56SDavid Gibson if (version_id < 1 || version_id > 1) { 14614be21d56SDavid Gibson fprintf(stderr, "htab_load() bad version\n"); 14624be21d56SDavid Gibson return -EINVAL; 14634be21d56SDavid Gibson } 14644be21d56SDavid Gibson 14654be21d56SDavid Gibson section_hdr = qemu_get_be32(f); 14664be21d56SDavid Gibson 14674be21d56SDavid Gibson if (section_hdr) { 14684be21d56SDavid Gibson /* First section, just the hash shift */ 14694be21d56SDavid Gibson if (spapr->htab_shift != section_hdr) { 1470613e7a76SBharata B Rao error_report("htab_shift mismatch: source %d target %d", 1471613e7a76SBharata B Rao section_hdr, spapr->htab_shift); 14724be21d56SDavid Gibson return -EINVAL; 14734be21d56SDavid Gibson } 14744be21d56SDavid Gibson return 0; 14754be21d56SDavid Gibson } 14764be21d56SDavid Gibson 1477e68cb8b4SAlexey Kardashevskiy if (!spapr->htab) { 1478e68cb8b4SAlexey Kardashevskiy assert(kvm_enabled()); 1479e68cb8b4SAlexey Kardashevskiy 1480e68cb8b4SAlexey Kardashevskiy fd = kvmppc_get_htab_fd(true); 1481e68cb8b4SAlexey Kardashevskiy if (fd < 0) { 1482e68cb8b4SAlexey Kardashevskiy fprintf(stderr, "Unable to open fd to restore KVM hash table: %s\n", 1483e68cb8b4SAlexey Kardashevskiy strerror(errno)); 1484e68cb8b4SAlexey Kardashevskiy } 1485e68cb8b4SAlexey Kardashevskiy } 1486e68cb8b4SAlexey Kardashevskiy 14874be21d56SDavid Gibson while (true) { 14884be21d56SDavid Gibson uint32_t index; 14894be21d56SDavid Gibson uint16_t n_valid, n_invalid; 14904be21d56SDavid Gibson 14914be21d56SDavid Gibson index = qemu_get_be32(f); 14924be21d56SDavid Gibson n_valid = qemu_get_be16(f); 14934be21d56SDavid Gibson n_invalid = qemu_get_be16(f); 14944be21d56SDavid Gibson 14954be21d56SDavid Gibson if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) { 14964be21d56SDavid Gibson /* End of Stream */ 14974be21d56SDavid Gibson break; 14984be21d56SDavid Gibson } 14994be21d56SDavid Gibson 1500e68cb8b4SAlexey Kardashevskiy if ((index + n_valid + n_invalid) > 15014be21d56SDavid Gibson (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) { 15024be21d56SDavid Gibson /* Bad index in stream */ 15034be21d56SDavid Gibson fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) " 1504e68cb8b4SAlexey Kardashevskiy "in htab stream (htab_shift=%d)\n", index, n_valid, n_invalid, 1505e68cb8b4SAlexey Kardashevskiy spapr->htab_shift); 15064be21d56SDavid Gibson return -EINVAL; 15074be21d56SDavid Gibson } 15084be21d56SDavid Gibson 1509e68cb8b4SAlexey Kardashevskiy if (spapr->htab) { 15104be21d56SDavid Gibson if (n_valid) { 15114be21d56SDavid Gibson qemu_get_buffer(f, HPTE(spapr->htab, index), 15124be21d56SDavid Gibson HASH_PTE_SIZE_64 * n_valid); 15134be21d56SDavid Gibson } 15144be21d56SDavid Gibson if (n_invalid) { 15154be21d56SDavid Gibson memset(HPTE(spapr->htab, index + n_valid), 0, 15164be21d56SDavid Gibson HASH_PTE_SIZE_64 * n_invalid); 15174be21d56SDavid Gibson } 1518e68cb8b4SAlexey Kardashevskiy } else { 1519e68cb8b4SAlexey Kardashevskiy int rc; 1520e68cb8b4SAlexey Kardashevskiy 1521e68cb8b4SAlexey Kardashevskiy assert(fd >= 0); 1522e68cb8b4SAlexey Kardashevskiy 1523e68cb8b4SAlexey Kardashevskiy rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid); 1524e68cb8b4SAlexey Kardashevskiy if (rc < 0) { 1525e68cb8b4SAlexey Kardashevskiy return rc; 1526e68cb8b4SAlexey Kardashevskiy } 1527e68cb8b4SAlexey Kardashevskiy } 1528e68cb8b4SAlexey Kardashevskiy } 1529e68cb8b4SAlexey Kardashevskiy 1530e68cb8b4SAlexey Kardashevskiy if (!spapr->htab) { 1531e68cb8b4SAlexey Kardashevskiy assert(fd >= 0); 1532e68cb8b4SAlexey Kardashevskiy close(fd); 15334be21d56SDavid Gibson } 15344be21d56SDavid Gibson 15354be21d56SDavid Gibson return 0; 15364be21d56SDavid Gibson } 15374be21d56SDavid Gibson 15384be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = { 15394be21d56SDavid Gibson .save_live_setup = htab_save_setup, 15404be21d56SDavid Gibson .save_live_iterate = htab_save_iterate, 15414be21d56SDavid Gibson .save_live_complete = htab_save_complete, 15424be21d56SDavid Gibson .load_state = htab_load, 15434be21d56SDavid Gibson }; 15444be21d56SDavid Gibson 15455b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device, 15465b2128d2SAlexander Graf Error **errp) 15475b2128d2SAlexander Graf { 15485b2128d2SAlexander Graf MachineState *machine = MACHINE(qdev_get_machine()); 15495b2128d2SAlexander Graf machine->boot_order = g_strdup(boot_device); 15505b2128d2SAlexander Graf } 15515b2128d2SAlexander Graf 1552bab99ea0SBharata B Rao static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu) 1553bab99ea0SBharata B Rao { 1554bab99ea0SBharata B Rao CPUPPCState *env = &cpu->env; 1555bab99ea0SBharata B Rao 1556bab99ea0SBharata B Rao /* Set time-base frequency to 512 MHz */ 1557bab99ea0SBharata B Rao cpu_ppc_tb_init(env, TIMEBASE_FREQ); 1558bab99ea0SBharata B Rao 1559bab99ea0SBharata B Rao /* PAPR always has exception vectors in RAM not ROM. To ensure this, 1560bab99ea0SBharata B Rao * MSR[IP] should never be set. 1561bab99ea0SBharata B Rao */ 1562bab99ea0SBharata B Rao env->msr_mask &= ~(1 << 6); 1563bab99ea0SBharata B Rao 1564bab99ea0SBharata B Rao /* Tell KVM that we're in PAPR mode */ 1565bab99ea0SBharata B Rao if (kvm_enabled()) { 1566bab99ea0SBharata B Rao kvmppc_set_papr(cpu); 1567bab99ea0SBharata B Rao } 1568bab99ea0SBharata B Rao 1569bab99ea0SBharata B Rao if (cpu->max_compat) { 1570bab99ea0SBharata B Rao if (ppc_set_compat(cpu, cpu->max_compat) < 0) { 1571bab99ea0SBharata B Rao exit(1); 1572bab99ea0SBharata B Rao } 1573bab99ea0SBharata B Rao } 1574bab99ea0SBharata B Rao 1575bab99ea0SBharata B Rao xics_cpu_setup(spapr->icp, cpu); 1576bab99ea0SBharata B Rao 1577bab99ea0SBharata B Rao qemu_register_reset(spapr_cpu_reset, cpu); 1578bab99ea0SBharata B Rao } 1579bab99ea0SBharata B Rao 1580224245bfSDavid Gibson /* 1581224245bfSDavid Gibson * Reset routine for LMB DR devices. 1582224245bfSDavid Gibson * 1583224245bfSDavid Gibson * Unlike PCI DR devices, LMB DR devices explicitly register this reset 1584224245bfSDavid Gibson * routine. Reset for PCI DR devices will be handled by PHB reset routine 1585224245bfSDavid Gibson * when it walks all its children devices. LMB devices reset occurs 1586224245bfSDavid Gibson * as part of spapr_ppc_reset(). 1587224245bfSDavid Gibson */ 1588224245bfSDavid Gibson static void spapr_drc_reset(void *opaque) 1589224245bfSDavid Gibson { 1590224245bfSDavid Gibson sPAPRDRConnector *drc = opaque; 1591224245bfSDavid Gibson DeviceState *d = DEVICE(drc); 1592224245bfSDavid Gibson 1593224245bfSDavid Gibson if (d) { 1594224245bfSDavid Gibson device_reset(d); 1595224245bfSDavid Gibson } 1596224245bfSDavid Gibson } 1597224245bfSDavid Gibson 1598224245bfSDavid Gibson static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr) 1599224245bfSDavid Gibson { 1600224245bfSDavid Gibson MachineState *machine = MACHINE(spapr); 1601224245bfSDavid Gibson uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE; 1602224245bfSDavid Gibson uint32_t nr_rma_lmbs = spapr->rma_size/lmb_size; 1603224245bfSDavid Gibson uint32_t nr_lmbs = machine->maxram_size/lmb_size - nr_rma_lmbs; 1604224245bfSDavid Gibson uint32_t nr_assigned_lmbs = machine->ram_size/lmb_size - nr_rma_lmbs; 1605224245bfSDavid Gibson int i; 1606224245bfSDavid Gibson 1607224245bfSDavid Gibson for (i = 0; i < nr_lmbs; i++) { 1608224245bfSDavid Gibson sPAPRDRConnector *drc; 1609224245bfSDavid Gibson uint64_t addr; 1610224245bfSDavid Gibson 1611224245bfSDavid Gibson if (i < nr_assigned_lmbs) { 1612224245bfSDavid Gibson addr = (i + nr_rma_lmbs) * lmb_size; 1613224245bfSDavid Gibson } else { 1614224245bfSDavid Gibson addr = (i - nr_assigned_lmbs) * lmb_size + 1615224245bfSDavid Gibson spapr->hotplug_memory.base; 1616224245bfSDavid Gibson } 1617224245bfSDavid Gibson drc = spapr_dr_connector_new(OBJECT(spapr), SPAPR_DR_CONNECTOR_TYPE_LMB, 1618224245bfSDavid Gibson addr/lmb_size); 1619224245bfSDavid Gibson qemu_register_reset(spapr_drc_reset, drc); 1620224245bfSDavid Gibson } 1621224245bfSDavid Gibson } 1622224245bfSDavid Gibson 1623224245bfSDavid Gibson /* 1624224245bfSDavid Gibson * If RAM size, maxmem size and individual node mem sizes aren't aligned 1625224245bfSDavid Gibson * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest 1626224245bfSDavid Gibson * since we can't support such unaligned sizes with DRCONF_MEMORY. 1627224245bfSDavid Gibson */ 1628224245bfSDavid Gibson static void spapr_validate_node_memory(MachineState *machine) 1629224245bfSDavid Gibson { 1630224245bfSDavid Gibson int i; 1631224245bfSDavid Gibson 1632224245bfSDavid Gibson if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE || 1633224245bfSDavid Gibson machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) { 1634224245bfSDavid Gibson error_report("Can't support memory configuration where RAM size " 1635224245bfSDavid Gibson "0x" RAM_ADDR_FMT " or maxmem size " 1636224245bfSDavid Gibson "0x" RAM_ADDR_FMT " isn't aligned to %llu MB", 1637224245bfSDavid Gibson machine->ram_size, machine->maxram_size, 1638224245bfSDavid Gibson SPAPR_MEMORY_BLOCK_SIZE/M_BYTE); 1639224245bfSDavid Gibson exit(EXIT_FAILURE); 1640224245bfSDavid Gibson } 1641224245bfSDavid Gibson 1642224245bfSDavid Gibson for (i = 0; i < nb_numa_nodes; i++) { 1643224245bfSDavid Gibson if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) { 1644224245bfSDavid Gibson error_report("Can't support memory configuration where memory size" 1645224245bfSDavid Gibson " %" PRIx64 " of node %d isn't aligned to %llu MB", 1646224245bfSDavid Gibson numa_info[i].node_mem, i, 1647224245bfSDavid Gibson SPAPR_MEMORY_BLOCK_SIZE/M_BYTE); 1648224245bfSDavid Gibson exit(EXIT_FAILURE); 1649224245bfSDavid Gibson } 1650224245bfSDavid Gibson } 1651224245bfSDavid Gibson } 1652224245bfSDavid Gibson 165353018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */ 16543ef96221SMarcel Apfelbaum static void ppc_spapr_init(MachineState *machine) 165553018216SPaolo Bonzini { 165628e02042SDavid Gibson sPAPRMachineState *spapr = SPAPR_MACHINE(machine); 1657224245bfSDavid Gibson sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); 16583ef96221SMarcel Apfelbaum const char *kernel_filename = machine->kernel_filename; 16593ef96221SMarcel Apfelbaum const char *kernel_cmdline = machine->kernel_cmdline; 16603ef96221SMarcel Apfelbaum const char *initrd_filename = machine->initrd_filename; 166153018216SPaolo Bonzini PowerPCCPU *cpu; 166253018216SPaolo Bonzini PCIHostState *phb; 166353018216SPaolo Bonzini int i; 166453018216SPaolo Bonzini MemoryRegion *sysmem = get_system_memory(); 166553018216SPaolo Bonzini MemoryRegion *ram = g_new(MemoryRegion, 1); 1666658fa66bSAlexey Kardashevskiy MemoryRegion *rma_region; 1667658fa66bSAlexey Kardashevskiy void *rma = NULL; 166853018216SPaolo Bonzini hwaddr rma_alloc_size; 1669b082d65aSAlexey Kardashevskiy hwaddr node0_size = spapr_node0_size(); 167053018216SPaolo Bonzini uint32_t initrd_base = 0; 167153018216SPaolo Bonzini long kernel_size = 0, initrd_size = 0; 1672b7d1f77aSBenjamin Herrenschmidt long load_limit, fw_size; 167316457e7fSBenjamin Herrenschmidt bool kernel_le = false; 167453018216SPaolo Bonzini char *filename; 167553018216SPaolo Bonzini 167653018216SPaolo Bonzini msi_supported = true; 167753018216SPaolo Bonzini 167853018216SPaolo Bonzini QLIST_INIT(&spapr->phbs); 167953018216SPaolo Bonzini 168053018216SPaolo Bonzini cpu_ppc_hypercall = emulate_spapr_hypercall; 168153018216SPaolo Bonzini 168253018216SPaolo Bonzini /* Allocate RMA if necessary */ 1683658fa66bSAlexey Kardashevskiy rma_alloc_size = kvmppc_alloc_rma(&rma); 168453018216SPaolo Bonzini 168553018216SPaolo Bonzini if (rma_alloc_size == -1) { 1686730fce59SThomas Huth error_report("Unable to create RMA"); 168753018216SPaolo Bonzini exit(1); 168853018216SPaolo Bonzini } 168953018216SPaolo Bonzini 1690c4177479SAlexey Kardashevskiy if (rma_alloc_size && (rma_alloc_size < node0_size)) { 169153018216SPaolo Bonzini spapr->rma_size = rma_alloc_size; 169253018216SPaolo Bonzini } else { 1693c4177479SAlexey Kardashevskiy spapr->rma_size = node0_size; 169453018216SPaolo Bonzini 169553018216SPaolo Bonzini /* With KVM, we don't actually know whether KVM supports an 169653018216SPaolo Bonzini * unbounded RMA (PR KVM) or is limited by the hash table size 169753018216SPaolo Bonzini * (HV KVM using VRMA), so we always assume the latter 169853018216SPaolo Bonzini * 169953018216SPaolo Bonzini * In that case, we also limit the initial allocations for RTAS 170053018216SPaolo Bonzini * etc... to 256M since we have no way to know what the VRMA size 170153018216SPaolo Bonzini * is going to be as it depends on the size of the hash table 170253018216SPaolo Bonzini * isn't determined yet. 170353018216SPaolo Bonzini */ 170453018216SPaolo Bonzini if (kvm_enabled()) { 170553018216SPaolo Bonzini spapr->vrma_adjust = 1; 170653018216SPaolo Bonzini spapr->rma_size = MIN(spapr->rma_size, 0x10000000); 170753018216SPaolo Bonzini } 170853018216SPaolo Bonzini } 170953018216SPaolo Bonzini 1710c4177479SAlexey Kardashevskiy if (spapr->rma_size > node0_size) { 1711c4177479SAlexey Kardashevskiy fprintf(stderr, "Error: Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")\n", 1712c4177479SAlexey Kardashevskiy spapr->rma_size); 1713c4177479SAlexey Kardashevskiy exit(1); 1714c4177479SAlexey Kardashevskiy } 1715c4177479SAlexey Kardashevskiy 1716b7d1f77aSBenjamin Herrenschmidt /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */ 1717b7d1f77aSBenjamin Herrenschmidt load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; 171853018216SPaolo Bonzini 171953018216SPaolo Bonzini /* We aim for a hash table of size 1/128 the size of RAM. The 172053018216SPaolo Bonzini * normal rule of thumb is 1/64 the size of RAM, but that's much 172153018216SPaolo Bonzini * more than needed for the Linux guests we support. */ 172253018216SPaolo Bonzini spapr->htab_shift = 18; /* Minimum architected size */ 172353018216SPaolo Bonzini while (spapr->htab_shift <= 46) { 1724ce881f77SBharata B Rao if ((1ULL << (spapr->htab_shift + 7)) >= machine->maxram_size) { 172553018216SPaolo Bonzini break; 172653018216SPaolo Bonzini } 172753018216SPaolo Bonzini spapr->htab_shift++; 172853018216SPaolo Bonzini } 172953018216SPaolo Bonzini 17307b565160SDavid Gibson /* Set up Interrupt Controller before we create the VCPUs */ 1731446f16a6SMarcel Apfelbaum spapr->icp = xics_system_init(machine, 17329e734e3dSBharata B Rao DIV_ROUND_UP(max_cpus * kvmppc_smt_threads(), 1733f303f117SGreg Kurz smp_threads), 17347b565160SDavid Gibson XICS_IRQS); 17357b565160SDavid Gibson 1736224245bfSDavid Gibson if (smc->dr_lmb_enabled) { 1737224245bfSDavid Gibson spapr_validate_node_memory(machine); 1738224245bfSDavid Gibson } 1739224245bfSDavid Gibson 174053018216SPaolo Bonzini /* init CPUs */ 174119fb2c36SBharata B Rao if (machine->cpu_model == NULL) { 174219fb2c36SBharata B Rao machine->cpu_model = kvm_enabled() ? "host" : "POWER7"; 174353018216SPaolo Bonzini } 174453018216SPaolo Bonzini for (i = 0; i < smp_cpus; i++) { 174519fb2c36SBharata B Rao cpu = cpu_ppc_init(machine->cpu_model); 174653018216SPaolo Bonzini if (cpu == NULL) { 174753018216SPaolo Bonzini fprintf(stderr, "Unable to find PowerPC CPU definition\n"); 174853018216SPaolo Bonzini exit(1); 174953018216SPaolo Bonzini } 1750bab99ea0SBharata B Rao spapr_cpu_init(spapr, cpu); 175153018216SPaolo Bonzini } 175253018216SPaolo Bonzini 1753026bfd89SDavid Gibson if (kvm_enabled()) { 1754026bfd89SDavid Gibson /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */ 1755026bfd89SDavid Gibson kvmppc_enable_logical_ci_hcalls(); 1756ef9971ddSAlexey Kardashevskiy kvmppc_enable_set_mode_hcall(); 1757026bfd89SDavid Gibson } 1758026bfd89SDavid Gibson 175953018216SPaolo Bonzini /* allocate RAM */ 1760f92f5da1SAlexey Kardashevskiy memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram", 1761fb164994SDavid Gibson machine->ram_size); 1762f92f5da1SAlexey Kardashevskiy memory_region_add_subregion(sysmem, 0, ram); 176353018216SPaolo Bonzini 1764658fa66bSAlexey Kardashevskiy if (rma_alloc_size && rma) { 1765658fa66bSAlexey Kardashevskiy rma_region = g_new(MemoryRegion, 1); 1766658fa66bSAlexey Kardashevskiy memory_region_init_ram_ptr(rma_region, NULL, "ppc_spapr.rma", 1767658fa66bSAlexey Kardashevskiy rma_alloc_size, rma); 1768658fa66bSAlexey Kardashevskiy vmstate_register_ram_global(rma_region); 1769658fa66bSAlexey Kardashevskiy memory_region_add_subregion(sysmem, 0, rma_region); 1770658fa66bSAlexey Kardashevskiy } 1771658fa66bSAlexey Kardashevskiy 17724a1c9cf0SBharata B Rao /* initialize hotplug memory address space */ 17734a1c9cf0SBharata B Rao if (machine->ram_size < machine->maxram_size) { 17744a1c9cf0SBharata B Rao ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size; 17754a1c9cf0SBharata B Rao 17764a1c9cf0SBharata B Rao if (machine->ram_slots > SPAPR_MAX_RAM_SLOTS) { 17774a1c9cf0SBharata B Rao error_report("unsupported amount of memory slots: %"PRIu64, 17784a1c9cf0SBharata B Rao machine->ram_slots); 17794a1c9cf0SBharata B Rao exit(EXIT_FAILURE); 17804a1c9cf0SBharata B Rao } 17814a1c9cf0SBharata B Rao 17824a1c9cf0SBharata B Rao spapr->hotplug_memory.base = ROUND_UP(machine->ram_size, 17834a1c9cf0SBharata B Rao SPAPR_HOTPLUG_MEM_ALIGN); 17844a1c9cf0SBharata B Rao memory_region_init(&spapr->hotplug_memory.mr, OBJECT(spapr), 17854a1c9cf0SBharata B Rao "hotplug-memory", hotplug_mem_size); 17864a1c9cf0SBharata B Rao memory_region_add_subregion(sysmem, spapr->hotplug_memory.base, 17874a1c9cf0SBharata B Rao &spapr->hotplug_memory.mr); 17884a1c9cf0SBharata B Rao } 17894a1c9cf0SBharata B Rao 1790224245bfSDavid Gibson if (smc->dr_lmb_enabled) { 1791224245bfSDavid Gibson spapr_create_lmb_dr_connectors(spapr); 1792224245bfSDavid Gibson } 1793224245bfSDavid Gibson 179453018216SPaolo Bonzini filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); 17954c56440dSStefan Weil if (!filename) { 1796730fce59SThomas Huth error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin"); 17974c56440dSStefan Weil exit(1); 17984c56440dSStefan Weil } 1799b7d1f77aSBenjamin Herrenschmidt spapr->rtas_size = get_image_size(filename); 1800b7d1f77aSBenjamin Herrenschmidt spapr->rtas_blob = g_malloc(spapr->rtas_size); 1801b7d1f77aSBenjamin Herrenschmidt if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) { 1802730fce59SThomas Huth error_report("Could not load LPAR rtas '%s'", filename); 180353018216SPaolo Bonzini exit(1); 180453018216SPaolo Bonzini } 180553018216SPaolo Bonzini if (spapr->rtas_size > RTAS_MAX_SIZE) { 1806730fce59SThomas Huth error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)", 18072f285bddSPeter Maydell (size_t)spapr->rtas_size, RTAS_MAX_SIZE); 180853018216SPaolo Bonzini exit(1); 180953018216SPaolo Bonzini } 181053018216SPaolo Bonzini g_free(filename); 181153018216SPaolo Bonzini 181253018216SPaolo Bonzini /* Set up EPOW events infrastructure */ 181353018216SPaolo Bonzini spapr_events_init(spapr); 181453018216SPaolo Bonzini 181512f42174SDavid Gibson /* Set up the RTC RTAS interfaces */ 181628df36a1SDavid Gibson spapr_rtc_create(spapr); 181712f42174SDavid Gibson 181853018216SPaolo Bonzini /* Set up VIO bus */ 181953018216SPaolo Bonzini spapr->vio_bus = spapr_vio_bus_init(); 182053018216SPaolo Bonzini 182153018216SPaolo Bonzini for (i = 0; i < MAX_SERIAL_PORTS; i++) { 182253018216SPaolo Bonzini if (serial_hds[i]) { 182353018216SPaolo Bonzini spapr_vty_create(spapr->vio_bus, serial_hds[i]); 182453018216SPaolo Bonzini } 182553018216SPaolo Bonzini } 182653018216SPaolo Bonzini 182753018216SPaolo Bonzini /* We always have at least the nvram device on VIO */ 182853018216SPaolo Bonzini spapr_create_nvram(spapr); 182953018216SPaolo Bonzini 183053018216SPaolo Bonzini /* Set up PCI */ 183153018216SPaolo Bonzini spapr_pci_rtas_init(); 183253018216SPaolo Bonzini 183389dfd6e1SDavid Gibson phb = spapr_create_phb(spapr, 0); 183453018216SPaolo Bonzini 183553018216SPaolo Bonzini for (i = 0; i < nb_nics; i++) { 183653018216SPaolo Bonzini NICInfo *nd = &nd_table[i]; 183753018216SPaolo Bonzini 183853018216SPaolo Bonzini if (!nd->model) { 183953018216SPaolo Bonzini nd->model = g_strdup("ibmveth"); 184053018216SPaolo Bonzini } 184153018216SPaolo Bonzini 184253018216SPaolo Bonzini if (strcmp(nd->model, "ibmveth") == 0) { 184353018216SPaolo Bonzini spapr_vlan_create(spapr->vio_bus, nd); 184453018216SPaolo Bonzini } else { 184529b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL); 184653018216SPaolo Bonzini } 184753018216SPaolo Bonzini } 184853018216SPaolo Bonzini 184953018216SPaolo Bonzini for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) { 185053018216SPaolo Bonzini spapr_vscsi_create(spapr->vio_bus); 185153018216SPaolo Bonzini } 185253018216SPaolo Bonzini 185353018216SPaolo Bonzini /* Graphics */ 185453018216SPaolo Bonzini if (spapr_vga_init(phb->bus)) { 185553018216SPaolo Bonzini spapr->has_graphics = true; 1856c6e76503SPaolo Bonzini machine->usb |= defaults_enabled() && !machine->usb_disabled; 185753018216SPaolo Bonzini } 185853018216SPaolo Bonzini 18594ee9ced9SMarcel Apfelbaum if (machine->usb) { 186053018216SPaolo Bonzini pci_create_simple(phb->bus, -1, "pci-ohci"); 1861c86580b8SMarkus Armbruster 186253018216SPaolo Bonzini if (spapr->has_graphics) { 1863c86580b8SMarkus Armbruster USBBus *usb_bus = usb_bus_find(-1); 1864c86580b8SMarkus Armbruster 1865c86580b8SMarkus Armbruster usb_create_simple(usb_bus, "usb-kbd"); 1866c86580b8SMarkus Armbruster usb_create_simple(usb_bus, "usb-mouse"); 186753018216SPaolo Bonzini } 186853018216SPaolo Bonzini } 186953018216SPaolo Bonzini 187053018216SPaolo Bonzini if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { 187153018216SPaolo Bonzini fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " 187253018216SPaolo Bonzini "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); 187353018216SPaolo Bonzini exit(1); 187453018216SPaolo Bonzini } 187553018216SPaolo Bonzini 187653018216SPaolo Bonzini if (kernel_filename) { 187753018216SPaolo Bonzini uint64_t lowaddr = 0; 187853018216SPaolo Bonzini 187953018216SPaolo Bonzini kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL, 188053018216SPaolo Bonzini NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0); 18813b66da82SAlexey Kardashevskiy if (kernel_size == ELF_LOAD_WRONG_ENDIAN) { 188216457e7fSBenjamin Herrenschmidt kernel_size = load_elf(kernel_filename, 188316457e7fSBenjamin Herrenschmidt translate_kernel_address, NULL, 188416457e7fSBenjamin Herrenschmidt NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0); 188516457e7fSBenjamin Herrenschmidt kernel_le = kernel_size > 0; 188616457e7fSBenjamin Herrenschmidt } 188716457e7fSBenjamin Herrenschmidt if (kernel_size < 0) { 18883b66da82SAlexey Kardashevskiy fprintf(stderr, "qemu: error loading %s: %s\n", 18893b66da82SAlexey Kardashevskiy kernel_filename, load_elf_strerror(kernel_size)); 189053018216SPaolo Bonzini exit(1); 189153018216SPaolo Bonzini } 189253018216SPaolo Bonzini 189353018216SPaolo Bonzini /* load initrd */ 189453018216SPaolo Bonzini if (initrd_filename) { 189553018216SPaolo Bonzini /* Try to locate the initrd in the gap between the kernel 189653018216SPaolo Bonzini * and the firmware. Add a bit of space just in case 189753018216SPaolo Bonzini */ 189853018216SPaolo Bonzini initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff; 189953018216SPaolo Bonzini initrd_size = load_image_targphys(initrd_filename, initrd_base, 190053018216SPaolo Bonzini load_limit - initrd_base); 190153018216SPaolo Bonzini if (initrd_size < 0) { 190253018216SPaolo Bonzini fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 190353018216SPaolo Bonzini initrd_filename); 190453018216SPaolo Bonzini exit(1); 190553018216SPaolo Bonzini } 190653018216SPaolo Bonzini } else { 190753018216SPaolo Bonzini initrd_base = 0; 190853018216SPaolo Bonzini initrd_size = 0; 190953018216SPaolo Bonzini } 191053018216SPaolo Bonzini } 191153018216SPaolo Bonzini 19128e7ea787SAndreas Färber if (bios_name == NULL) { 19138e7ea787SAndreas Färber bios_name = FW_FILE_NAME; 19148e7ea787SAndreas Färber } 19158e7ea787SAndreas Färber filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 19164c56440dSStefan Weil if (!filename) { 191768fea5a0SThomas Huth error_report("Could not find LPAR firmware '%s'", bios_name); 19184c56440dSStefan Weil exit(1); 19194c56440dSStefan Weil } 192053018216SPaolo Bonzini fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); 192168fea5a0SThomas Huth if (fw_size <= 0) { 192268fea5a0SThomas Huth error_report("Could not load LPAR firmware '%s'", filename); 192353018216SPaolo Bonzini exit(1); 192453018216SPaolo Bonzini } 192553018216SPaolo Bonzini g_free(filename); 192653018216SPaolo Bonzini 192728e02042SDavid Gibson /* FIXME: Should register things through the MachineState's qdev 192828e02042SDavid Gibson * interface, this is a legacy from the sPAPREnvironment structure 192928e02042SDavid Gibson * which predated MachineState but had a similar function */ 19304be21d56SDavid Gibson vmstate_register(NULL, 0, &vmstate_spapr, spapr); 19314be21d56SDavid Gibson register_savevm_live(NULL, "spapr/htab", -1, 1, 19324be21d56SDavid Gibson &savevm_htab_handlers, spapr); 19334be21d56SDavid Gibson 193453018216SPaolo Bonzini /* Prepare the device tree */ 19353bbf37f2SAndreas Färber spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size, 193616457e7fSBenjamin Herrenschmidt kernel_size, kernel_le, 193731fe14d1SNathan Fontenot kernel_cmdline, 193831fe14d1SNathan Fontenot spapr->check_exception_irq); 193953018216SPaolo Bonzini assert(spapr->fdt_skel != NULL); 19405b2128d2SAlexander Graf 194146503c2bSMichael Roth /* used by RTAS */ 194246503c2bSMichael Roth QTAILQ_INIT(&spapr->ccs_list); 194346503c2bSMichael Roth qemu_register_reset(spapr_ccs_reset_hook, spapr); 194446503c2bSMichael Roth 19455b2128d2SAlexander Graf qemu_register_boot_set(spapr_boot_set, spapr); 194653018216SPaolo Bonzini } 194753018216SPaolo Bonzini 1948135a129aSAneesh Kumar K.V static int spapr_kvm_type(const char *vm_type) 1949135a129aSAneesh Kumar K.V { 1950135a129aSAneesh Kumar K.V if (!vm_type) { 1951135a129aSAneesh Kumar K.V return 0; 1952135a129aSAneesh Kumar K.V } 1953135a129aSAneesh Kumar K.V 1954135a129aSAneesh Kumar K.V if (!strcmp(vm_type, "HV")) { 1955135a129aSAneesh Kumar K.V return 1; 1956135a129aSAneesh Kumar K.V } 1957135a129aSAneesh Kumar K.V 1958135a129aSAneesh Kumar K.V if (!strcmp(vm_type, "PR")) { 1959135a129aSAneesh Kumar K.V return 2; 1960135a129aSAneesh Kumar K.V } 1961135a129aSAneesh Kumar K.V 1962135a129aSAneesh Kumar K.V error_report("Unknown kvm-type specified '%s'", vm_type); 1963135a129aSAneesh Kumar K.V exit(1); 1964135a129aSAneesh Kumar K.V } 1965135a129aSAneesh Kumar K.V 196671461b0fSAlexey Kardashevskiy /* 1967627b84f4SGonglei * Implementation of an interface to adjust firmware path 196871461b0fSAlexey Kardashevskiy * for the bootindex property handling. 196971461b0fSAlexey Kardashevskiy */ 197071461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus, 197171461b0fSAlexey Kardashevskiy DeviceState *dev) 197271461b0fSAlexey Kardashevskiy { 197371461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \ 197471461b0fSAlexey Kardashevskiy ((type *)object_dynamic_cast(OBJECT(obj), (name))) 197571461b0fSAlexey Kardashevskiy SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE); 197671461b0fSAlexey Kardashevskiy sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE); 197771461b0fSAlexey Kardashevskiy 197871461b0fSAlexey Kardashevskiy if (d) { 197971461b0fSAlexey Kardashevskiy void *spapr = CAST(void, bus->parent, "spapr-vscsi"); 198071461b0fSAlexey Kardashevskiy VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI); 198171461b0fSAlexey Kardashevskiy USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE); 198271461b0fSAlexey Kardashevskiy 198371461b0fSAlexey Kardashevskiy if (spapr) { 198471461b0fSAlexey Kardashevskiy /* 198571461b0fSAlexey Kardashevskiy * Replace "channel@0/disk@0,0" with "disk@8000000000000000": 198671461b0fSAlexey Kardashevskiy * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun 198771461b0fSAlexey Kardashevskiy * in the top 16 bits of the 64-bit LUN 198871461b0fSAlexey Kardashevskiy */ 198971461b0fSAlexey Kardashevskiy unsigned id = 0x8000 | (d->id << 8) | d->lun; 199071461b0fSAlexey Kardashevskiy return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), 199171461b0fSAlexey Kardashevskiy (uint64_t)id << 48); 199271461b0fSAlexey Kardashevskiy } else if (virtio) { 199371461b0fSAlexey Kardashevskiy /* 199471461b0fSAlexey Kardashevskiy * We use SRP luns of the form 01000000 | (target << 8) | lun 199571461b0fSAlexey Kardashevskiy * in the top 32 bits of the 64-bit LUN 199671461b0fSAlexey Kardashevskiy * Note: the quote above is from SLOF and it is wrong, 199771461b0fSAlexey Kardashevskiy * the actual binding is: 199871461b0fSAlexey Kardashevskiy * swap 0100 or 10 << or 20 << ( target lun-id -- srplun ) 199971461b0fSAlexey Kardashevskiy */ 200071461b0fSAlexey Kardashevskiy unsigned id = 0x1000000 | (d->id << 16) | d->lun; 200171461b0fSAlexey Kardashevskiy return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), 200271461b0fSAlexey Kardashevskiy (uint64_t)id << 32); 200371461b0fSAlexey Kardashevskiy } else if (usb) { 200471461b0fSAlexey Kardashevskiy /* 200571461b0fSAlexey Kardashevskiy * We use SRP luns of the form 01000000 | (usb-port << 16) | lun 200671461b0fSAlexey Kardashevskiy * in the top 32 bits of the 64-bit LUN 200771461b0fSAlexey Kardashevskiy */ 200871461b0fSAlexey Kardashevskiy unsigned usb_port = atoi(usb->port->path); 200971461b0fSAlexey Kardashevskiy unsigned id = 0x1000000 | (usb_port << 16) | d->lun; 201071461b0fSAlexey Kardashevskiy return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev), 201171461b0fSAlexey Kardashevskiy (uint64_t)id << 32); 201271461b0fSAlexey Kardashevskiy } 201371461b0fSAlexey Kardashevskiy } 201471461b0fSAlexey Kardashevskiy 201571461b0fSAlexey Kardashevskiy if (phb) { 201671461b0fSAlexey Kardashevskiy /* Replace "pci" with "pci@800000020000000" */ 201771461b0fSAlexey Kardashevskiy return g_strdup_printf("pci@%"PRIX64, phb->buid); 201871461b0fSAlexey Kardashevskiy } 201971461b0fSAlexey Kardashevskiy 202071461b0fSAlexey Kardashevskiy return NULL; 202171461b0fSAlexey Kardashevskiy } 202271461b0fSAlexey Kardashevskiy 202323825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp) 202423825581SEduardo Habkost { 202528e02042SDavid Gibson sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 202623825581SEduardo Habkost 202728e02042SDavid Gibson return g_strdup(spapr->kvm_type); 202823825581SEduardo Habkost } 202923825581SEduardo Habkost 203023825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp) 203123825581SEduardo Habkost { 203228e02042SDavid Gibson sPAPRMachineState *spapr = SPAPR_MACHINE(obj); 203323825581SEduardo Habkost 203428e02042SDavid Gibson g_free(spapr->kvm_type); 203528e02042SDavid Gibson spapr->kvm_type = g_strdup(value); 203623825581SEduardo Habkost } 203723825581SEduardo Habkost 203823825581SEduardo Habkost static void spapr_machine_initfn(Object *obj) 203923825581SEduardo Habkost { 204023825581SEduardo Habkost object_property_add_str(obj, "kvm-type", 204123825581SEduardo Habkost spapr_get_kvm_type, spapr_set_kvm_type, NULL); 204249d2e648SMarcel Apfelbaum object_property_set_description(obj, "kvm-type", 204349d2e648SMarcel Apfelbaum "Specifies the KVM virtualization mode (HV, PR)", 204449d2e648SMarcel Apfelbaum NULL); 204523825581SEduardo Habkost } 204623825581SEduardo Habkost 204734316482SAlexey Kardashevskiy static void ppc_cpu_do_nmi_on_cpu(void *arg) 204834316482SAlexey Kardashevskiy { 204934316482SAlexey Kardashevskiy CPUState *cs = arg; 205034316482SAlexey Kardashevskiy 205134316482SAlexey Kardashevskiy cpu_synchronize_state(cs); 205234316482SAlexey Kardashevskiy ppc_cpu_do_system_reset(cs); 205334316482SAlexey Kardashevskiy } 205434316482SAlexey Kardashevskiy 205534316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp) 205634316482SAlexey Kardashevskiy { 205734316482SAlexey Kardashevskiy CPUState *cs; 205834316482SAlexey Kardashevskiy 205934316482SAlexey Kardashevskiy CPU_FOREACH(cs) { 206034316482SAlexey Kardashevskiy async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, cs); 206134316482SAlexey Kardashevskiy } 206234316482SAlexey Kardashevskiy } 206334316482SAlexey Kardashevskiy 2064c20d332aSBharata B Rao static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size, 2065c20d332aSBharata B Rao uint32_t node, Error **errp) 2066c20d332aSBharata B Rao { 2067c20d332aSBharata B Rao sPAPRDRConnector *drc; 2068c20d332aSBharata B Rao sPAPRDRConnectorClass *drck; 2069c20d332aSBharata B Rao uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE; 2070c20d332aSBharata B Rao int i, fdt_offset, fdt_size; 2071c20d332aSBharata B Rao void *fdt; 2072c20d332aSBharata B Rao 2073c20d332aSBharata B Rao /* 2074c20d332aSBharata B Rao * Check for DRC connectors and send hotplug notification to the 2075c20d332aSBharata B Rao * guest only in case of hotplugged memory. This allows cold plugged 2076c20d332aSBharata B Rao * memory to be specified at boot time. 2077c20d332aSBharata B Rao */ 2078c20d332aSBharata B Rao if (!dev->hotplugged) { 2079c20d332aSBharata B Rao return; 2080c20d332aSBharata B Rao } 2081c20d332aSBharata B Rao 2082c20d332aSBharata B Rao for (i = 0; i < nr_lmbs; i++) { 2083c20d332aSBharata B Rao drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, 2084c20d332aSBharata B Rao addr/SPAPR_MEMORY_BLOCK_SIZE); 2085c20d332aSBharata B Rao g_assert(drc); 2086c20d332aSBharata B Rao 2087c20d332aSBharata B Rao fdt = create_device_tree(&fdt_size); 2088c20d332aSBharata B Rao fdt_offset = spapr_populate_memory_node(fdt, node, addr, 2089c20d332aSBharata B Rao SPAPR_MEMORY_BLOCK_SIZE); 2090c20d332aSBharata B Rao 2091c20d332aSBharata B Rao drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); 2092c20d332aSBharata B Rao drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp); 2093c20d332aSBharata B Rao spapr_hotplug_req_add_event(drc); 2094c20d332aSBharata B Rao addr += SPAPR_MEMORY_BLOCK_SIZE; 2095c20d332aSBharata B Rao } 2096c20d332aSBharata B Rao } 2097c20d332aSBharata B Rao 2098c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev, 2099c20d332aSBharata B Rao uint32_t node, Error **errp) 2100c20d332aSBharata B Rao { 2101c20d332aSBharata B Rao Error *local_err = NULL; 2102c20d332aSBharata B Rao sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev); 2103c20d332aSBharata B Rao PCDIMMDevice *dimm = PC_DIMM(dev); 2104c20d332aSBharata B Rao PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); 2105c20d332aSBharata B Rao MemoryRegion *mr = ddc->get_memory_region(dimm); 2106c20d332aSBharata B Rao uint64_t align = memory_region_get_alignment(mr); 2107c20d332aSBharata B Rao uint64_t size = memory_region_size(mr); 2108c20d332aSBharata B Rao uint64_t addr; 2109c20d332aSBharata B Rao 2110c20d332aSBharata B Rao if (size % SPAPR_MEMORY_BLOCK_SIZE) { 2111c20d332aSBharata B Rao error_setg(&local_err, "Hotplugged memory size must be a multiple of " 2112c20d332aSBharata B Rao "%lld MB", SPAPR_MEMORY_BLOCK_SIZE/M_BYTE); 2113c20d332aSBharata B Rao goto out; 2114c20d332aSBharata B Rao } 2115c20d332aSBharata B Rao 2116c20d332aSBharata B Rao pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err); 2117c20d332aSBharata B Rao if (local_err) { 2118c20d332aSBharata B Rao goto out; 2119c20d332aSBharata B Rao } 2120c20d332aSBharata B Rao 2121c20d332aSBharata B Rao addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err); 2122c20d332aSBharata B Rao if (local_err) { 2123c20d332aSBharata B Rao pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr); 2124c20d332aSBharata B Rao goto out; 2125c20d332aSBharata B Rao } 2126c20d332aSBharata B Rao 2127c20d332aSBharata B Rao spapr_add_lmbs(dev, addr, size, node, &error_abort); 2128c20d332aSBharata B Rao 2129c20d332aSBharata B Rao out: 2130c20d332aSBharata B Rao error_propagate(errp, local_err); 2131c20d332aSBharata B Rao } 2132c20d332aSBharata B Rao 2133c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev, 2134c20d332aSBharata B Rao DeviceState *dev, Error **errp) 2135c20d332aSBharata B Rao { 2136c20d332aSBharata B Rao sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine()); 2137c20d332aSBharata B Rao 2138c20d332aSBharata B Rao if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 2139*b556854bSBharata B Rao int node; 2140c20d332aSBharata B Rao 2141c20d332aSBharata B Rao if (!smc->dr_lmb_enabled) { 2142c20d332aSBharata B Rao error_setg(errp, "Memory hotplug not supported for this machine"); 2143c20d332aSBharata B Rao return; 2144c20d332aSBharata B Rao } 2145c20d332aSBharata B Rao node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, errp); 2146c20d332aSBharata B Rao if (*errp) { 2147c20d332aSBharata B Rao return; 2148c20d332aSBharata B Rao } 2149c20d332aSBharata B Rao 2150*b556854bSBharata B Rao /* 2151*b556854bSBharata B Rao * Currently PowerPC kernel doesn't allow hot-adding memory to 2152*b556854bSBharata B Rao * memory-less node, but instead will silently add the memory 2153*b556854bSBharata B Rao * to the first node that has some memory. This causes two 2154*b556854bSBharata B Rao * unexpected behaviours for the user. 2155*b556854bSBharata B Rao * 2156*b556854bSBharata B Rao * - Memory gets hotplugged to a different node than what the user 2157*b556854bSBharata B Rao * specified. 2158*b556854bSBharata B Rao * - Since pc-dimm subsystem in QEMU still thinks that memory belongs 2159*b556854bSBharata B Rao * to memory-less node, a reboot will set things accordingly 2160*b556854bSBharata B Rao * and the previously hotplugged memory now ends in the right node. 2161*b556854bSBharata B Rao * This appears as if some memory moved from one node to another. 2162*b556854bSBharata B Rao * 2163*b556854bSBharata B Rao * So until kernel starts supporting memory hotplug to memory-less 2164*b556854bSBharata B Rao * nodes, just prevent such attempts upfront in QEMU. 2165*b556854bSBharata B Rao */ 2166*b556854bSBharata B Rao if (nb_numa_nodes && !numa_info[node].node_mem) { 2167*b556854bSBharata B Rao error_setg(errp, "Can't hotplug memory to memory-less node %d", 2168*b556854bSBharata B Rao node); 2169*b556854bSBharata B Rao return; 2170*b556854bSBharata B Rao } 2171*b556854bSBharata B Rao 2172c20d332aSBharata B Rao spapr_memory_plug(hotplug_dev, dev, node, errp); 2173c20d332aSBharata B Rao } 2174c20d332aSBharata B Rao } 2175c20d332aSBharata B Rao 2176c20d332aSBharata B Rao static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev, 2177c20d332aSBharata B Rao DeviceState *dev, Error **errp) 2178c20d332aSBharata B Rao { 2179c20d332aSBharata B Rao if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 2180c20d332aSBharata B Rao error_setg(errp, "Memory hot unplug not supported by sPAPR"); 2181c20d332aSBharata B Rao } 2182c20d332aSBharata B Rao } 2183c20d332aSBharata B Rao 2184c20d332aSBharata B Rao static HotplugHandler *spapr_get_hotpug_handler(MachineState *machine, 2185c20d332aSBharata B Rao DeviceState *dev) 2186c20d332aSBharata B Rao { 2187c20d332aSBharata B Rao if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 2188c20d332aSBharata B Rao return HOTPLUG_HANDLER(machine); 2189c20d332aSBharata B Rao } 2190c20d332aSBharata B Rao return NULL; 2191c20d332aSBharata B Rao } 2192c20d332aSBharata B Rao 219329ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data) 219453018216SPaolo Bonzini { 219529ee3247SAlexey Kardashevskiy MachineClass *mc = MACHINE_CLASS(oc); 2196224245bfSDavid Gibson sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc); 219771461b0fSAlexey Kardashevskiy FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); 219834316482SAlexey Kardashevskiy NMIClass *nc = NMI_CLASS(oc); 2199c20d332aSBharata B Rao HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); 220029ee3247SAlexey Kardashevskiy 2201958db90cSMarcel Apfelbaum mc->init = ppc_spapr_init; 2202958db90cSMarcel Apfelbaum mc->reset = ppc_spapr_reset; 2203958db90cSMarcel Apfelbaum mc->block_default_type = IF_SCSI; 220438b02bd8SAlexey Kardashevskiy mc->max_cpus = MAX_CPUMASK_BITS; 2205958db90cSMarcel Apfelbaum mc->no_parallel = 1; 22065b2128d2SAlexander Graf mc->default_boot_order = ""; 2207a34944feSNikunj A Dadhania mc->default_ram_size = 512 * M_BYTE; 2208958db90cSMarcel Apfelbaum mc->kvm_type = spapr_kvm_type; 22099e3f9733SAlexander Graf mc->has_dynamic_sysbus = true; 2210e4024630SLaurent Vivier mc->pci_allow_0_address = true; 2211c20d332aSBharata B Rao mc->get_hotplug_handler = spapr_get_hotpug_handler; 2212c20d332aSBharata B Rao hc->plug = spapr_machine_device_plug; 2213c20d332aSBharata B Rao hc->unplug = spapr_machine_device_unplug; 221400b4fbe2SMarcel Apfelbaum 2215224245bfSDavid Gibson smc->dr_lmb_enabled = false; 221671461b0fSAlexey Kardashevskiy fwc->get_dev_path = spapr_get_fw_dev_path; 221734316482SAlexey Kardashevskiy nc->nmi_monitor_handler = spapr_nmi; 221853018216SPaolo Bonzini } 221953018216SPaolo Bonzini 222029ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = { 222129ee3247SAlexey Kardashevskiy .name = TYPE_SPAPR_MACHINE, 222229ee3247SAlexey Kardashevskiy .parent = TYPE_MACHINE, 22234aee7362SDavid Gibson .abstract = true, 22246ca1502eSAlexey Kardashevskiy .instance_size = sizeof(sPAPRMachineState), 222523825581SEduardo Habkost .instance_init = spapr_machine_initfn, 2226183930c0SDavid Gibson .class_size = sizeof(sPAPRMachineClass), 222729ee3247SAlexey Kardashevskiy .class_init = spapr_machine_class_init, 222871461b0fSAlexey Kardashevskiy .interfaces = (InterfaceInfo[]) { 222971461b0fSAlexey Kardashevskiy { TYPE_FW_PATH_PROVIDER }, 223034316482SAlexey Kardashevskiy { TYPE_NMI }, 2231c20d332aSBharata B Rao { TYPE_HOTPLUG_HANDLER }, 223271461b0fSAlexey Kardashevskiy { } 223371461b0fSAlexey Kardashevskiy }, 223429ee3247SAlexey Kardashevskiy }; 223529ee3247SAlexey Kardashevskiy 223638ff32c6SEduardo Habkost #define SPAPR_COMPAT_2_3 \ 22377619c7b0SMichael Roth HW_COMPAT_2_3 \ 22387619c7b0SMichael Roth {\ 22397619c7b0SMichael Roth .driver = "spapr-pci-host-bridge",\ 22407619c7b0SMichael Roth .property = "dynamic-reconfiguration",\ 22417619c7b0SMichael Roth .value = "off",\ 22427619c7b0SMichael Roth }, 224338ff32c6SEduardo Habkost 2244b194df47SAlexey Kardashevskiy #define SPAPR_COMPAT_2_2 \ 224538ff32c6SEduardo Habkost SPAPR_COMPAT_2_3 \ 22464dfd8eaaSEduardo Habkost HW_COMPAT_2_2 \ 2247b194df47SAlexey Kardashevskiy {\ 2248b194df47SAlexey Kardashevskiy .driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\ 2249b194df47SAlexey Kardashevskiy .property = "mem_win_size",\ 2250b194df47SAlexey Kardashevskiy .value = "0x20000000",\ 2251dd754bafSEduardo Habkost }, 2252b194df47SAlexey Kardashevskiy 2253b194df47SAlexey Kardashevskiy #define SPAPR_COMPAT_2_1 \ 22544dfd8eaaSEduardo Habkost SPAPR_COMPAT_2_2 \ 22554dfd8eaaSEduardo Habkost HW_COMPAT_2_1 2256b194df47SAlexey Kardashevskiy 2257d25228e7SJason Wang static void spapr_compat_2_3(Object *obj) 2258d25228e7SJason Wang { 2259ff14e817SDr. David Alan Gilbert savevm_skip_section_footers(); 226013d16814SJuan Quintela global_state_set_optional(); 2261d25228e7SJason Wang } 2262d25228e7SJason Wang 2263b0e966d0SJason Wang static void spapr_compat_2_2(Object *obj) 2264b0e966d0SJason Wang { 2265d25228e7SJason Wang spapr_compat_2_3(obj); 2266b0e966d0SJason Wang } 2267b0e966d0SJason Wang 2268b0e966d0SJason Wang static void spapr_compat_2_1(Object *obj) 2269b0e966d0SJason Wang { 2270b0e966d0SJason Wang spapr_compat_2_2(obj); 2271b0e966d0SJason Wang } 2272b0e966d0SJason Wang 2273d25228e7SJason Wang static void spapr_machine_2_3_instance_init(Object *obj) 2274d25228e7SJason Wang { 2275d25228e7SJason Wang spapr_compat_2_3(obj); 2276d25228e7SJason Wang spapr_machine_initfn(obj); 2277d25228e7SJason Wang } 2278d25228e7SJason Wang 2279b0e966d0SJason Wang static void spapr_machine_2_2_instance_init(Object *obj) 2280b0e966d0SJason Wang { 2281b0e966d0SJason Wang spapr_compat_2_2(obj); 2282b0e966d0SJason Wang spapr_machine_initfn(obj); 2283b0e966d0SJason Wang } 2284b0e966d0SJason Wang 2285b0e966d0SJason Wang static void spapr_machine_2_1_instance_init(Object *obj) 2286b0e966d0SJason Wang { 2287b0e966d0SJason Wang spapr_compat_2_1(obj); 2288b0e966d0SJason Wang spapr_machine_initfn(obj); 2289b0e966d0SJason Wang } 2290b0e966d0SJason Wang 22916026db45SAlexey Kardashevskiy static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data) 22926026db45SAlexey Kardashevskiy { 22936026db45SAlexey Kardashevskiy MachineClass *mc = MACHINE_CLASS(oc); 229468a27b20SMichael S. Tsirkin static GlobalProperty compat_props[] = { 2295dd754bafSEduardo Habkost SPAPR_COMPAT_2_1 229668a27b20SMichael S. Tsirkin { /* end of list */ } 229768a27b20SMichael S. Tsirkin }; 22986026db45SAlexey Kardashevskiy 22996026db45SAlexey Kardashevskiy mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1"; 230068a27b20SMichael S. Tsirkin mc->compat_props = compat_props; 23016026db45SAlexey Kardashevskiy } 23026026db45SAlexey Kardashevskiy 23036026db45SAlexey Kardashevskiy static const TypeInfo spapr_machine_2_1_info = { 2304b9f072d0SEduardo Habkost .name = MACHINE_TYPE_NAME("pseries-2.1"), 23056026db45SAlexey Kardashevskiy .parent = TYPE_SPAPR_MACHINE, 23066026db45SAlexey Kardashevskiy .class_init = spapr_machine_2_1_class_init, 2307b0e966d0SJason Wang .instance_init = spapr_machine_2_1_instance_init, 23086026db45SAlexey Kardashevskiy }; 23096026db45SAlexey Kardashevskiy 23104aee7362SDavid Gibson static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data) 23114aee7362SDavid Gibson { 2312b194df47SAlexey Kardashevskiy static GlobalProperty compat_props[] = { 2313dd754bafSEduardo Habkost SPAPR_COMPAT_2_2 2314b194df47SAlexey Kardashevskiy { /* end of list */ } 2315b194df47SAlexey Kardashevskiy }; 23164aee7362SDavid Gibson MachineClass *mc = MACHINE_CLASS(oc); 23174aee7362SDavid Gibson 23184aee7362SDavid Gibson mc->desc = "pSeries Logical Partition (PAPR compliant) v2.2"; 2319b194df47SAlexey Kardashevskiy mc->compat_props = compat_props; 23204aee7362SDavid Gibson } 23214aee7362SDavid Gibson 23224aee7362SDavid Gibson static const TypeInfo spapr_machine_2_2_info = { 2323b9f072d0SEduardo Habkost .name = MACHINE_TYPE_NAME("pseries-2.2"), 23244aee7362SDavid Gibson .parent = TYPE_SPAPR_MACHINE, 23254aee7362SDavid Gibson .class_init = spapr_machine_2_2_class_init, 2326b0e966d0SJason Wang .instance_init = spapr_machine_2_2_instance_init, 23274aee7362SDavid Gibson }; 23284aee7362SDavid Gibson 23293dab0244SAlexey Kardashevskiy static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data) 23303dab0244SAlexey Kardashevskiy { 2331a1a45612SDavid Gibson static GlobalProperty compat_props[] = { 23327619c7b0SMichael Roth SPAPR_COMPAT_2_3 2333a1a45612SDavid Gibson { /* end of list */ } 2334a1a45612SDavid Gibson }; 23353dab0244SAlexey Kardashevskiy MachineClass *mc = MACHINE_CLASS(oc); 23363dab0244SAlexey Kardashevskiy 23373dab0244SAlexey Kardashevskiy mc->desc = "pSeries Logical Partition (PAPR compliant) v2.3"; 2338a1a45612SDavid Gibson mc->compat_props = compat_props; 23393dab0244SAlexey Kardashevskiy } 23403dab0244SAlexey Kardashevskiy 23413dab0244SAlexey Kardashevskiy static const TypeInfo spapr_machine_2_3_info = { 2342b9f072d0SEduardo Habkost .name = MACHINE_TYPE_NAME("pseries-2.3"), 23433dab0244SAlexey Kardashevskiy .parent = TYPE_SPAPR_MACHINE, 23443dab0244SAlexey Kardashevskiy .class_init = spapr_machine_2_3_class_init, 2345d25228e7SJason Wang .instance_init = spapr_machine_2_3_instance_init, 2346d25228e7SJason Wang }; 2347d25228e7SJason Wang 2348d25228e7SJason Wang static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data) 2349d25228e7SJason Wang { 2350d25228e7SJason Wang MachineClass *mc = MACHINE_CLASS(oc); 2351d25228e7SJason Wang 2352d25228e7SJason Wang mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4"; 2353d25228e7SJason Wang mc->alias = "pseries"; 2354fb0fc8f6SDavid Gibson mc->is_default = 0; 2355d25228e7SJason Wang } 2356d25228e7SJason Wang 2357d25228e7SJason Wang static const TypeInfo spapr_machine_2_4_info = { 2358b9f072d0SEduardo Habkost .name = MACHINE_TYPE_NAME("pseries-2.4"), 2359d25228e7SJason Wang .parent = TYPE_SPAPR_MACHINE, 2360d25228e7SJason Wang .class_init = spapr_machine_2_4_class_init, 23613dab0244SAlexey Kardashevskiy }; 23623dab0244SAlexey Kardashevskiy 2363fb0fc8f6SDavid Gibson static void spapr_machine_2_5_class_init(ObjectClass *oc, void *data) 2364fb0fc8f6SDavid Gibson { 2365fb0fc8f6SDavid Gibson MachineClass *mc = MACHINE_CLASS(oc); 2366224245bfSDavid Gibson sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc); 2367fb0fc8f6SDavid Gibson 2368fb0fc8f6SDavid Gibson mc->name = "pseries-2.5"; 2369fb0fc8f6SDavid Gibson mc->desc = "pSeries Logical Partition (PAPR compliant) v2.5"; 2370fb0fc8f6SDavid Gibson mc->alias = "pseries"; 2371fb0fc8f6SDavid Gibson mc->is_default = 1; 2372224245bfSDavid Gibson smc->dr_lmb_enabled = true; 2373fb0fc8f6SDavid Gibson } 2374fb0fc8f6SDavid Gibson 2375fb0fc8f6SDavid Gibson static const TypeInfo spapr_machine_2_5_info = { 2376fb0fc8f6SDavid Gibson .name = MACHINE_TYPE_NAME("pseries-2.5"), 2377fb0fc8f6SDavid Gibson .parent = TYPE_SPAPR_MACHINE, 2378fb0fc8f6SDavid Gibson .class_init = spapr_machine_2_5_class_init, 2379fb0fc8f6SDavid Gibson }; 2380fb0fc8f6SDavid Gibson 238129ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void) 238229ee3247SAlexey Kardashevskiy { 238329ee3247SAlexey Kardashevskiy type_register_static(&spapr_machine_info); 23846026db45SAlexey Kardashevskiy type_register_static(&spapr_machine_2_1_info); 23854aee7362SDavid Gibson type_register_static(&spapr_machine_2_2_info); 23863dab0244SAlexey Kardashevskiy type_register_static(&spapr_machine_2_3_info); 2387d25228e7SJason Wang type_register_static(&spapr_machine_2_4_info); 2388fb0fc8f6SDavid Gibson type_register_static(&spapr_machine_2_5_info); 238929ee3247SAlexey Kardashevskiy } 239029ee3247SAlexey Kardashevskiy 239129ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types) 2392