xref: /openbmc/qemu/hw/ppc/spapr.c (revision e0eeb4a2)
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  */
270d75590dSPeter Maydell #include "qemu/osdep.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
2953018216SPaolo Bonzini #include "sysemu/sysemu.h"
30e35704baSEduardo Habkost #include "sysemu/numa.h"
3153018216SPaolo Bonzini #include "hw/hw.h"
3203dd024fSPaolo Bonzini #include "qemu/log.h"
3371461b0fSAlexey Kardashevskiy #include "hw/fw-path-provider.h"
3453018216SPaolo Bonzini #include "elf.h"
3553018216SPaolo Bonzini #include "net/net.h"
36ad440b4aSAndrew Jones #include "sysemu/device_tree.h"
37fa1d36dfSMarkus Armbruster #include "sysemu/block-backend.h"
3853018216SPaolo Bonzini #include "sysemu/cpus.h"
3953018216SPaolo Bonzini #include "sysemu/kvm.h"
40c20d332aSBharata B Rao #include "sysemu/device_tree.h"
4153018216SPaolo Bonzini #include "kvm_ppc.h"
42ff14e817SDr. David Alan Gilbert #include "migration/migration.h"
434be21d56SDavid Gibson #include "mmu-hash64.h"
443794d548SAlexey Kardashevskiy #include "qom/cpu.h"
4553018216SPaolo Bonzini 
4653018216SPaolo Bonzini #include "hw/boards.h"
470d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
4853018216SPaolo Bonzini #include "hw/loader.h"
4953018216SPaolo Bonzini 
507804c353SCédric Le Goater #include "hw/ppc/fdt.h"
510d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
520d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
530d09e41aSPaolo Bonzini #include "hw/pci-host/spapr.h"
540d09e41aSPaolo Bonzini #include "hw/ppc/xics.h"
5553018216SPaolo Bonzini #include "hw/pci/msi.h"
5653018216SPaolo Bonzini 
5753018216SPaolo Bonzini #include "hw/pci/pci.h"
5871461b0fSAlexey Kardashevskiy #include "hw/scsi/scsi.h"
5971461b0fSAlexey Kardashevskiy #include "hw/virtio/virtio-scsi.h"
6053018216SPaolo Bonzini 
6153018216SPaolo Bonzini #include "exec/address-spaces.h"
6253018216SPaolo Bonzini #include "hw/usb.h"
6353018216SPaolo Bonzini #include "qemu/config-file.h"
64135a129aSAneesh Kumar K.V #include "qemu/error-report.h"
652a6593cbSAlexey Kardashevskiy #include "trace.h"
6634316482SAlexey Kardashevskiy #include "hw/nmi.h"
6753018216SPaolo Bonzini 
6868a27b20SMichael S. Tsirkin #include "hw/compat.h"
69f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
7094a94e4cSBharata B Rao #include "hw/ppc/spapr_cpu_core.h"
712474bfd4SIgor Mammedov #include "qmp-commands.h"
7268a27b20SMichael S. Tsirkin 
7353018216SPaolo Bonzini #include <libfdt.h>
7453018216SPaolo Bonzini 
7553018216SPaolo Bonzini /* SLOF memory layout:
7653018216SPaolo Bonzini  *
7753018216SPaolo Bonzini  * SLOF raw image loaded at 0, copies its romfs right below the flat
7853018216SPaolo Bonzini  * device-tree, then position SLOF itself 31M below that
7953018216SPaolo Bonzini  *
8053018216SPaolo Bonzini  * So we set FW_OVERHEAD to 40MB which should account for all of that
8153018216SPaolo Bonzini  * and more
8253018216SPaolo Bonzini  *
8353018216SPaolo Bonzini  * We load our kernel at 4M, leaving space for SLOF initial image
8453018216SPaolo Bonzini  */
8538b02bd8SAlexey Kardashevskiy #define FDT_MAX_SIZE            0x100000
8653018216SPaolo Bonzini #define RTAS_MAX_SIZE           0x10000
87b7d1f77aSBenjamin Herrenschmidt #define RTAS_MAX_ADDR           0x80000000 /* RTAS must stay below that */
8853018216SPaolo Bonzini #define FW_MAX_SIZE             0x400000
8953018216SPaolo Bonzini #define FW_FILE_NAME            "slof.bin"
9053018216SPaolo Bonzini #define FW_OVERHEAD             0x2800000
9153018216SPaolo Bonzini #define KERNEL_LOAD_ADDR        FW_MAX_SIZE
9253018216SPaolo Bonzini 
9353018216SPaolo Bonzini #define MIN_RMA_SLOF            128UL
9453018216SPaolo Bonzini 
9553018216SPaolo Bonzini #define PHANDLE_XICP            0x00001111
9653018216SPaolo Bonzini 
9753018216SPaolo Bonzini #define HTAB_SIZE(spapr)        (1ULL << ((spapr)->htab_shift))
9853018216SPaolo Bonzini 
99c04d6cfaSAnthony Liguori static XICSState *try_create_xics(const char *type, int nr_servers,
10034f2af3dSMarkus Armbruster                                   int nr_irqs, Error **errp)
101c04d6cfaSAnthony Liguori {
10234f2af3dSMarkus Armbruster     Error *err = NULL;
103c04d6cfaSAnthony Liguori     DeviceState *dev;
104c04d6cfaSAnthony Liguori 
105c04d6cfaSAnthony Liguori     dev = qdev_create(NULL, type);
106c04d6cfaSAnthony Liguori     qdev_prop_set_uint32(dev, "nr_servers", nr_servers);
107c04d6cfaSAnthony Liguori     qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs);
10834f2af3dSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
10934f2af3dSMarkus Armbruster     if (err) {
11034f2af3dSMarkus Armbruster         error_propagate(errp, err);
11134f2af3dSMarkus Armbruster         object_unparent(OBJECT(dev));
112c04d6cfaSAnthony Liguori         return NULL;
113c04d6cfaSAnthony Liguori     }
1145a3d7b23SAlexey Kardashevskiy     return XICS_COMMON(dev);
115c04d6cfaSAnthony Liguori }
116c04d6cfaSAnthony Liguori 
117446f16a6SMarcel Apfelbaum static XICSState *xics_system_init(MachineState *machine,
1181e49182dSDavid Gibson                                    int nr_servers, int nr_irqs, Error **errp)
119c04d6cfaSAnthony Liguori {
12027f24582SBenjamin Herrenschmidt     XICSState *xics = NULL;
121c04d6cfaSAnthony Liguori 
12211ad93f6SDavid Gibson     if (kvm_enabled()) {
12334f2af3dSMarkus Armbruster         Error *err = NULL;
12434f2af3dSMarkus Armbruster 
125446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
12627f24582SBenjamin Herrenschmidt             xics = try_create_xics(TYPE_XICS_SPAPR_KVM, nr_servers, nr_irqs,
127161deaf2SBenjamin Herrenschmidt                                    &err);
12811ad93f6SDavid Gibson         }
12927f24582SBenjamin Herrenschmidt         if (machine_kernel_irqchip_required(machine) && !xics) {
130b83baa60SMarkus Armbruster             error_reportf_err(err,
131b83baa60SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
132b83baa60SMarkus Armbruster         } else {
133903a41d3SStefano Dong (董兴水)             error_free(err);
13411ad93f6SDavid Gibson         }
135b83baa60SMarkus Armbruster     }
13611ad93f6SDavid Gibson 
13727f24582SBenjamin Herrenschmidt     if (!xics) {
13827f24582SBenjamin Herrenschmidt         xics = try_create_xics(TYPE_XICS_SPAPR, nr_servers, nr_irqs, errp);
139c04d6cfaSAnthony Liguori     }
140c04d6cfaSAnthony Liguori 
14127f24582SBenjamin Herrenschmidt     return xics;
142c04d6cfaSAnthony Liguori }
143c04d6cfaSAnthony Liguori 
144833d4668SAlexey Kardashevskiy static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
145833d4668SAlexey Kardashevskiy                                   int smt_threads)
146833d4668SAlexey Kardashevskiy {
147833d4668SAlexey Kardashevskiy     int i, ret = 0;
148833d4668SAlexey Kardashevskiy     uint32_t servers_prop[smt_threads];
149833d4668SAlexey Kardashevskiy     uint32_t gservers_prop[smt_threads * 2];
150833d4668SAlexey Kardashevskiy     int index = ppc_get_vcpu_dt_id(cpu);
151833d4668SAlexey Kardashevskiy 
1526d9412eaSAlexey Kardashevskiy     if (cpu->cpu_version) {
1534bce526eSLaurent Dufour         ret = fdt_setprop_cell(fdt, offset, "cpu-version", cpu->cpu_version);
1546d9412eaSAlexey Kardashevskiy         if (ret < 0) {
1556d9412eaSAlexey Kardashevskiy             return ret;
1566d9412eaSAlexey Kardashevskiy         }
1576d9412eaSAlexey Kardashevskiy     }
1586d9412eaSAlexey Kardashevskiy 
159833d4668SAlexey Kardashevskiy     /* Build interrupt servers and gservers properties */
160833d4668SAlexey Kardashevskiy     for (i = 0; i < smt_threads; i++) {
161833d4668SAlexey Kardashevskiy         servers_prop[i] = cpu_to_be32(index + i);
162833d4668SAlexey Kardashevskiy         /* Hack, direct the group queues back to cpu 0 */
163833d4668SAlexey Kardashevskiy         gservers_prop[i*2] = cpu_to_be32(index + i);
164833d4668SAlexey Kardashevskiy         gservers_prop[i*2 + 1] = 0;
165833d4668SAlexey Kardashevskiy     }
166833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-server#s",
167833d4668SAlexey Kardashevskiy                       servers_prop, sizeof(servers_prop));
168833d4668SAlexey Kardashevskiy     if (ret < 0) {
169833d4668SAlexey Kardashevskiy         return ret;
170833d4668SAlexey Kardashevskiy     }
171833d4668SAlexey Kardashevskiy     ret = fdt_setprop(fdt, offset, "ibm,ppc-interrupt-gserver#s",
172833d4668SAlexey Kardashevskiy                       gservers_prop, sizeof(gservers_prop));
173833d4668SAlexey Kardashevskiy 
174833d4668SAlexey Kardashevskiy     return ret;
175833d4668SAlexey Kardashevskiy }
176833d4668SAlexey Kardashevskiy 
1770da6f3feSBharata B Rao static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, CPUState *cs)
1780da6f3feSBharata B Rao {
1790da6f3feSBharata B Rao     int ret = 0;
1800da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
1810da6f3feSBharata B Rao     int index = ppc_get_vcpu_dt_id(cpu);
1820da6f3feSBharata B Rao     uint32_t associativity[] = {cpu_to_be32(0x5),
1830da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1840da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1850da6f3feSBharata B Rao                                 cpu_to_be32(0x0),
1860da6f3feSBharata B Rao                                 cpu_to_be32(cs->numa_node),
1870da6f3feSBharata B Rao                                 cpu_to_be32(index)};
1880da6f3feSBharata B Rao 
1890da6f3feSBharata B Rao     /* Advertise NUMA via ibm,associativity */
1900da6f3feSBharata B Rao     if (nb_numa_nodes > 1) {
1910da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
1920da6f3feSBharata B Rao                           sizeof(associativity));
1930da6f3feSBharata B Rao     }
1940da6f3feSBharata B Rao 
1950da6f3feSBharata B Rao     return ret;
1960da6f3feSBharata B Rao }
1970da6f3feSBharata B Rao 
19828e02042SDavid Gibson static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
19953018216SPaolo Bonzini {
20082677ed2SAlexey Kardashevskiy     int ret = 0, offset, cpus_offset;
20182677ed2SAlexey Kardashevskiy     CPUState *cs;
20253018216SPaolo Bonzini     char cpu_model[32];
20353018216SPaolo Bonzini     int smt = kvmppc_smt_threads();
20453018216SPaolo Bonzini     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
20553018216SPaolo Bonzini 
20682677ed2SAlexey Kardashevskiy     CPU_FOREACH(cs) {
20782677ed2SAlexey Kardashevskiy         PowerPCCPU *cpu = POWERPC_CPU(cs);
20882677ed2SAlexey Kardashevskiy         DeviceClass *dc = DEVICE_GET_CLASS(cs);
20982677ed2SAlexey Kardashevskiy         int index = ppc_get_vcpu_dt_id(cpu);
21053018216SPaolo Bonzini 
2110f20ba62SAlexey Kardashevskiy         if ((index % smt) != 0) {
21253018216SPaolo Bonzini             continue;
21353018216SPaolo Bonzini         }
21453018216SPaolo Bonzini 
21582677ed2SAlexey Kardashevskiy         snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
21653018216SPaolo Bonzini 
21782677ed2SAlexey Kardashevskiy         cpus_offset = fdt_path_offset(fdt, "/cpus");
21882677ed2SAlexey Kardashevskiy         if (cpus_offset < 0) {
21982677ed2SAlexey Kardashevskiy             cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"),
22082677ed2SAlexey Kardashevskiy                                           "cpus");
22182677ed2SAlexey Kardashevskiy             if (cpus_offset < 0) {
22282677ed2SAlexey Kardashevskiy                 return cpus_offset;
22382677ed2SAlexey Kardashevskiy             }
22482677ed2SAlexey Kardashevskiy         }
22582677ed2SAlexey Kardashevskiy         offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
22682677ed2SAlexey Kardashevskiy         if (offset < 0) {
22782677ed2SAlexey Kardashevskiy             offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
22853018216SPaolo Bonzini             if (offset < 0) {
22953018216SPaolo Bonzini                 return offset;
23053018216SPaolo Bonzini             }
23182677ed2SAlexey Kardashevskiy         }
23253018216SPaolo Bonzini 
2330da6f3feSBharata B Rao         ret = fdt_setprop(fdt, offset, "ibm,pft-size",
2340da6f3feSBharata B Rao                           pft_size_prop, sizeof(pft_size_prop));
23553018216SPaolo Bonzini         if (ret < 0) {
23653018216SPaolo Bonzini             return ret;
23753018216SPaolo Bonzini         }
23853018216SPaolo Bonzini 
2390da6f3feSBharata B Rao         ret = spapr_fixup_cpu_numa_dt(fdt, offset, cs);
24053018216SPaolo Bonzini         if (ret < 0) {
24153018216SPaolo Bonzini             return ret;
24253018216SPaolo Bonzini         }
243833d4668SAlexey Kardashevskiy 
24482677ed2SAlexey Kardashevskiy         ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
2452a48d993SAlexey Kardashevskiy                                      ppc_get_compat_smt_threads(cpu));
246833d4668SAlexey Kardashevskiy         if (ret < 0) {
247833d4668SAlexey Kardashevskiy             return ret;
248833d4668SAlexey Kardashevskiy         }
24953018216SPaolo Bonzini     }
25053018216SPaolo Bonzini     return ret;
25153018216SPaolo Bonzini }
25253018216SPaolo Bonzini 
253b082d65aSAlexey Kardashevskiy static hwaddr spapr_node0_size(void)
254b082d65aSAlexey Kardashevskiy {
255fb164994SDavid Gibson     MachineState *machine = MACHINE(qdev_get_machine());
256fb164994SDavid Gibson 
257b082d65aSAlexey Kardashevskiy     if (nb_numa_nodes) {
258b082d65aSAlexey Kardashevskiy         int i;
259b082d65aSAlexey Kardashevskiy         for (i = 0; i < nb_numa_nodes; ++i) {
260b082d65aSAlexey Kardashevskiy             if (numa_info[i].node_mem) {
261fb164994SDavid Gibson                 return MIN(pow2floor(numa_info[i].node_mem),
262fb164994SDavid Gibson                            machine->ram_size);
263b082d65aSAlexey Kardashevskiy             }
264b082d65aSAlexey Kardashevskiy         }
265b082d65aSAlexey Kardashevskiy     }
266fb164994SDavid Gibson     return machine->ram_size;
267b082d65aSAlexey Kardashevskiy }
268b082d65aSAlexey Kardashevskiy 
269a1d59c0fSAlexey Kardashevskiy static void add_str(GString *s, const gchar *s1)
270a1d59c0fSAlexey Kardashevskiy {
271a1d59c0fSAlexey Kardashevskiy     g_string_append_len(s, s1, strlen(s1) + 1);
272a1d59c0fSAlexey Kardashevskiy }
27353018216SPaolo Bonzini 
2743bbf37f2SAndreas Färber static void *spapr_create_fdt_skel(hwaddr initrd_base,
27553018216SPaolo Bonzini                                    hwaddr initrd_size,
27653018216SPaolo Bonzini                                    hwaddr kernel_size,
27716457e7fSBenjamin Herrenschmidt                                    bool little_endian,
27853018216SPaolo Bonzini                                    const char *kernel_cmdline,
27953018216SPaolo Bonzini                                    uint32_t epow_irq)
28053018216SPaolo Bonzini {
28153018216SPaolo Bonzini     void *fdt;
28253018216SPaolo Bonzini     uint32_t start_prop = cpu_to_be32(initrd_base);
28353018216SPaolo Bonzini     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
284a1d59c0fSAlexey Kardashevskiy     GString *hypertas = g_string_sized_new(256);
285a1d59c0fSAlexey Kardashevskiy     GString *qemu_hypertas = g_string_sized_new(256);
28653018216SPaolo Bonzini     uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
2879e734e3dSBharata B Rao     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(max_cpus)};
28853018216SPaolo Bonzini     unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
289ef951443SNikunj A Dadhania     char *buf;
29053018216SPaolo Bonzini 
291a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-pft");
292a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-term");
293a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-dabr");
294a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-interrupt");
295a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-tce");
296a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-vio");
297a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-splpar");
298a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-bulk");
299a1d59c0fSAlexey Kardashevskiy     add_str(hypertas, "hcall-set-mode");
3006cc09e26SThomas Huth     add_str(hypertas, "hcall-sprg0");
3016cc09e26SThomas Huth     add_str(hypertas, "hcall-copy");
3026cc09e26SThomas Huth     add_str(hypertas, "hcall-debug");
303a1d59c0fSAlexey Kardashevskiy     add_str(qemu_hypertas, "hcall-memop1");
304a1d59c0fSAlexey Kardashevskiy 
30553018216SPaolo Bonzini     fdt = g_malloc0(FDT_MAX_SIZE);
30653018216SPaolo Bonzini     _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
30753018216SPaolo Bonzini 
30853018216SPaolo Bonzini     if (kernel_size) {
30953018216SPaolo Bonzini         _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
31053018216SPaolo Bonzini     }
31153018216SPaolo Bonzini     if (initrd_size) {
31253018216SPaolo Bonzini         _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
31353018216SPaolo Bonzini     }
31453018216SPaolo Bonzini     _FDT((fdt_finish_reservemap(fdt)));
31553018216SPaolo Bonzini 
31653018216SPaolo Bonzini     /* Root node */
31753018216SPaolo Bonzini     _FDT((fdt_begin_node(fdt, "")));
31853018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "device_type", "chrp")));
31953018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
320fa388916SAnthony Liguori     _FDT((fdt_property_string(fdt, "compatible", "qemu,pseries")));
32153018216SPaolo Bonzini 
322ef951443SNikunj A Dadhania     /*
323ef951443SNikunj A Dadhania      * Add info to guest to indentify which host is it being run on
324ef951443SNikunj A Dadhania      * and what is the uuid of the guest
325ef951443SNikunj A Dadhania      */
326ef951443SNikunj A Dadhania     if (kvmppc_get_host_model(&buf)) {
327ef951443SNikunj A Dadhania         _FDT((fdt_property_string(fdt, "host-model", buf)));
328ef951443SNikunj A Dadhania         g_free(buf);
329ef951443SNikunj A Dadhania     }
330ef951443SNikunj A Dadhania     if (kvmppc_get_host_serial(&buf)) {
331ef951443SNikunj A Dadhania         _FDT((fdt_property_string(fdt, "host-serial", buf)));
332ef951443SNikunj A Dadhania         g_free(buf);
333ef951443SNikunj A Dadhania     }
334ef951443SNikunj A Dadhania 
3359c5ce8dbSFam Zheng     buf = qemu_uuid_unparse_strdup(&qemu_uuid);
336ef951443SNikunj A Dadhania 
337ef951443SNikunj A Dadhania     _FDT((fdt_property_string(fdt, "vm,uuid", buf)));
3383dc0a66dSAlexey Kardashevskiy     if (qemu_uuid_set) {
3393dc0a66dSAlexey Kardashevskiy         _FDT((fdt_property_string(fdt, "system-id", buf)));
3403dc0a66dSAlexey Kardashevskiy     }
341ef951443SNikunj A Dadhania     g_free(buf);
342ef951443SNikunj A Dadhania 
3432c1aaa81SSam Bobroff     if (qemu_get_vm_name()) {
3442c1aaa81SSam Bobroff         _FDT((fdt_property_string(fdt, "ibm,partition-name",
3452c1aaa81SSam Bobroff                                   qemu_get_vm_name())));
3462c1aaa81SSam Bobroff     }
3472c1aaa81SSam Bobroff 
34853018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
34953018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
35053018216SPaolo Bonzini 
35153018216SPaolo Bonzini     /* /chosen */
35253018216SPaolo Bonzini     _FDT((fdt_begin_node(fdt, "chosen")));
35353018216SPaolo Bonzini 
35453018216SPaolo Bonzini     /* Set Form1_affinity */
35553018216SPaolo Bonzini     _FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
35653018216SPaolo Bonzini 
35753018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
35853018216SPaolo Bonzini     _FDT((fdt_property(fdt, "linux,initrd-start",
35953018216SPaolo Bonzini                        &start_prop, sizeof(start_prop))));
36053018216SPaolo Bonzini     _FDT((fdt_property(fdt, "linux,initrd-end",
36153018216SPaolo Bonzini                        &end_prop, sizeof(end_prop))));
36253018216SPaolo Bonzini     if (kernel_size) {
36353018216SPaolo Bonzini         uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
36453018216SPaolo Bonzini                               cpu_to_be64(kernel_size) };
36553018216SPaolo Bonzini 
36653018216SPaolo Bonzini         _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
36716457e7fSBenjamin Herrenschmidt         if (little_endian) {
36816457e7fSBenjamin Herrenschmidt             _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0)));
36916457e7fSBenjamin Herrenschmidt         }
37053018216SPaolo Bonzini     }
371cc84c0f3SAvik Sil     if (boot_menu) {
372cc84c0f3SAvik Sil         _FDT((fdt_property_cell(fdt, "qemu,boot-menu", boot_menu)));
373cc84c0f3SAvik Sil     }
37453018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "qemu,graphic-width", graphic_width)));
37553018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "qemu,graphic-height", graphic_height)));
37653018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "qemu,graphic-depth", graphic_depth)));
37753018216SPaolo Bonzini 
37853018216SPaolo Bonzini     _FDT((fdt_end_node(fdt)));
37953018216SPaolo Bonzini 
38053018216SPaolo Bonzini     /* RTAS */
38153018216SPaolo Bonzini     _FDT((fdt_begin_node(fdt, "rtas")));
38253018216SPaolo Bonzini 
383da95324eSAlexey Kardashevskiy     if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
384da95324eSAlexey Kardashevskiy         add_str(hypertas, "hcall-multi-tce");
385da95324eSAlexey Kardashevskiy     }
386a1d59c0fSAlexey Kardashevskiy     _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas->str,
387a1d59c0fSAlexey Kardashevskiy                        hypertas->len)));
388a1d59c0fSAlexey Kardashevskiy     g_string_free(hypertas, TRUE);
389a1d59c0fSAlexey Kardashevskiy     _FDT((fdt_property(fdt, "qemu,hypertas-functions", qemu_hypertas->str,
390a1d59c0fSAlexey Kardashevskiy                        qemu_hypertas->len)));
391a1d59c0fSAlexey Kardashevskiy     g_string_free(qemu_hypertas, TRUE);
39253018216SPaolo Bonzini 
39353018216SPaolo Bonzini     _FDT((fdt_property(fdt, "ibm,associativity-reference-points",
39453018216SPaolo Bonzini         refpoints, sizeof(refpoints))));
39553018216SPaolo Bonzini 
39653018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
39779853e18STyrel Datwyler     _FDT((fdt_property_cell(fdt, "rtas-event-scan-rate",
39879853e18STyrel Datwyler                             RTAS_EVENT_SCAN_RATE)));
39953018216SPaolo Bonzini 
400226419d6SMichael S. Tsirkin     if (msi_nonbroken) {
401a95f9922SSam Bobroff         _FDT((fdt_property(fdt, "ibm,change-msix-capable", NULL, 0)));
402a95f9922SSam Bobroff     }
403a95f9922SSam Bobroff 
4042e14072fSNikunj A Dadhania     /*
4059d632f5fSzhanghailiang      * According to PAPR, rtas ibm,os-term does not guarantee a return
4062e14072fSNikunj A Dadhania      * back to the guest cpu.
4072e14072fSNikunj A Dadhania      *
4082e14072fSNikunj A Dadhania      * While an additional ibm,extended-os-term property indicates that
4092e14072fSNikunj A Dadhania      * rtas call return will always occur. Set this property.
4102e14072fSNikunj A Dadhania      */
4112e14072fSNikunj A Dadhania     _FDT((fdt_property(fdt, "ibm,extended-os-term", NULL, 0)));
4122e14072fSNikunj A Dadhania 
41353018216SPaolo Bonzini     _FDT((fdt_end_node(fdt)));
41453018216SPaolo Bonzini 
41553018216SPaolo Bonzini     /* interrupt controller */
41653018216SPaolo Bonzini     _FDT((fdt_begin_node(fdt, "interrupt-controller")));
41753018216SPaolo Bonzini 
41853018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "device_type",
41953018216SPaolo Bonzini                               "PowerPC-External-Interrupt-Presentation")));
42053018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
42153018216SPaolo Bonzini     _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
42253018216SPaolo Bonzini     _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
42353018216SPaolo Bonzini                        interrupt_server_ranges_prop,
42453018216SPaolo Bonzini                        sizeof(interrupt_server_ranges_prop))));
42553018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#interrupt-cells", 2)));
42653018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP)));
42753018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "phandle", PHANDLE_XICP)));
42853018216SPaolo Bonzini 
42953018216SPaolo Bonzini     _FDT((fdt_end_node(fdt)));
43053018216SPaolo Bonzini 
43153018216SPaolo Bonzini     /* vdevice */
43253018216SPaolo Bonzini     _FDT((fdt_begin_node(fdt, "vdevice")));
43353018216SPaolo Bonzini 
43453018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
43553018216SPaolo Bonzini     _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
43653018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
43753018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
43853018216SPaolo Bonzini     _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
43953018216SPaolo Bonzini     _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
44053018216SPaolo Bonzini 
44153018216SPaolo Bonzini     _FDT((fdt_end_node(fdt)));
44253018216SPaolo Bonzini 
44353018216SPaolo Bonzini     /* event-sources */
44453018216SPaolo Bonzini     spapr_events_fdt_skel(fdt, epow_irq);
44553018216SPaolo Bonzini 
446f7d69146SAlexander Graf     /* /hypervisor node */
447f7d69146SAlexander Graf     if (kvm_enabled()) {
448f7d69146SAlexander Graf         uint8_t hypercall[16];
449f7d69146SAlexander Graf 
450f7d69146SAlexander Graf         /* indicate KVM hypercall interface */
451f7d69146SAlexander Graf         _FDT((fdt_begin_node(fdt, "hypervisor")));
452f7d69146SAlexander Graf         _FDT((fdt_property_string(fdt, "compatible", "linux,kvm")));
453f7d69146SAlexander Graf         if (kvmppc_has_cap_fixup_hcalls()) {
454f7d69146SAlexander Graf             /*
455f7d69146SAlexander Graf              * Older KVM versions with older guest kernels were broken with the
456f7d69146SAlexander Graf              * magic page, don't allow the guest to map it.
457f7d69146SAlexander Graf              */
4580ddbd053SAlexey Kardashevskiy             if (!kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
4590ddbd053SAlexey Kardashevskiy                                       sizeof(hypercall))) {
460f7d69146SAlexander Graf                 _FDT((fdt_property(fdt, "hcall-instructions", hypercall,
461f7d69146SAlexander Graf                                    sizeof(hypercall))));
462f7d69146SAlexander Graf             }
4630ddbd053SAlexey Kardashevskiy         }
464f7d69146SAlexander Graf         _FDT((fdt_end_node(fdt)));
465f7d69146SAlexander Graf     }
466f7d69146SAlexander Graf 
46753018216SPaolo Bonzini     _FDT((fdt_end_node(fdt))); /* close root node */
46853018216SPaolo Bonzini     _FDT((fdt_finish(fdt)));
46953018216SPaolo Bonzini 
47053018216SPaolo Bonzini     return fdt;
47153018216SPaolo Bonzini }
47253018216SPaolo Bonzini 
47303d196b7SBharata B Rao static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
47426a8c353SAlexey Kardashevskiy                                        hwaddr size)
47526a8c353SAlexey Kardashevskiy {
47626a8c353SAlexey Kardashevskiy     uint32_t associativity[] = {
47726a8c353SAlexey Kardashevskiy         cpu_to_be32(0x4), /* length */
47826a8c353SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(0x0),
479c3b4f589SAlexey Kardashevskiy         cpu_to_be32(0x0), cpu_to_be32(nodeid)
48026a8c353SAlexey Kardashevskiy     };
48126a8c353SAlexey Kardashevskiy     char mem_name[32];
48226a8c353SAlexey Kardashevskiy     uint64_t mem_reg_property[2];
48326a8c353SAlexey Kardashevskiy     int off;
48426a8c353SAlexey Kardashevskiy 
48526a8c353SAlexey Kardashevskiy     mem_reg_property[0] = cpu_to_be64(start);
48626a8c353SAlexey Kardashevskiy     mem_reg_property[1] = cpu_to_be64(size);
48726a8c353SAlexey Kardashevskiy 
48826a8c353SAlexey Kardashevskiy     sprintf(mem_name, "memory@" TARGET_FMT_lx, start);
48926a8c353SAlexey Kardashevskiy     off = fdt_add_subnode(fdt, 0, mem_name);
49026a8c353SAlexey Kardashevskiy     _FDT(off);
49126a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
49226a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property,
49326a8c353SAlexey Kardashevskiy                       sizeof(mem_reg_property))));
49426a8c353SAlexey Kardashevskiy     _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
49526a8c353SAlexey Kardashevskiy                       sizeof(associativity))));
49603d196b7SBharata B Rao     return off;
49726a8c353SAlexey Kardashevskiy }
49826a8c353SAlexey Kardashevskiy 
49928e02042SDavid Gibson static int spapr_populate_memory(sPAPRMachineState *spapr, void *fdt)
50053018216SPaolo Bonzini {
501fb164994SDavid Gibson     MachineState *machine = MACHINE(spapr);
5027db8a127SAlexey Kardashevskiy     hwaddr mem_start, node_size;
5037db8a127SAlexey Kardashevskiy     int i, nb_nodes = nb_numa_nodes;
5047db8a127SAlexey Kardashevskiy     NodeInfo *nodes = numa_info;
5057db8a127SAlexey Kardashevskiy     NodeInfo ramnode;
50653018216SPaolo Bonzini 
5077db8a127SAlexey Kardashevskiy     /* No NUMA nodes, assume there is just one node with whole RAM */
5087db8a127SAlexey Kardashevskiy     if (!nb_numa_nodes) {
5097db8a127SAlexey Kardashevskiy         nb_nodes = 1;
510fb164994SDavid Gibson         ramnode.node_mem = machine->ram_size;
5117db8a127SAlexey Kardashevskiy         nodes = &ramnode;
5125fe269b1SPaul Mackerras     }
51353018216SPaolo Bonzini 
5147db8a127SAlexey Kardashevskiy     for (i = 0, mem_start = 0; i < nb_nodes; ++i) {
5157db8a127SAlexey Kardashevskiy         if (!nodes[i].node_mem) {
5167db8a127SAlexey Kardashevskiy             continue;
51753018216SPaolo Bonzini         }
518fb164994SDavid Gibson         if (mem_start >= machine->ram_size) {
5195fe269b1SPaul Mackerras             node_size = 0;
5205fe269b1SPaul Mackerras         } else {
5217db8a127SAlexey Kardashevskiy             node_size = nodes[i].node_mem;
522fb164994SDavid Gibson             if (node_size > machine->ram_size - mem_start) {
523fb164994SDavid Gibson                 node_size = machine->ram_size - mem_start;
5245fe269b1SPaul Mackerras             }
5255fe269b1SPaul Mackerras         }
5267db8a127SAlexey Kardashevskiy         if (!mem_start) {
5277db8a127SAlexey Kardashevskiy             /* ppc_spapr_init() checks for rma_size <= node0_size already */
528e8f986fcSBharata B Rao             spapr_populate_memory_node(fdt, i, 0, spapr->rma_size);
5297db8a127SAlexey Kardashevskiy             mem_start += spapr->rma_size;
5307db8a127SAlexey Kardashevskiy             node_size -= spapr->rma_size;
5317db8a127SAlexey Kardashevskiy         }
5326010818cSAlexey Kardashevskiy         for ( ; node_size; ) {
5336010818cSAlexey Kardashevskiy             hwaddr sizetmp = pow2floor(node_size);
5346010818cSAlexey Kardashevskiy 
5356010818cSAlexey Kardashevskiy             /* mem_start != 0 here */
5366010818cSAlexey Kardashevskiy             if (ctzl(mem_start) < ctzl(sizetmp)) {
5376010818cSAlexey Kardashevskiy                 sizetmp = 1ULL << ctzl(mem_start);
5386010818cSAlexey Kardashevskiy             }
5396010818cSAlexey Kardashevskiy 
5406010818cSAlexey Kardashevskiy             spapr_populate_memory_node(fdt, i, mem_start, sizetmp);
5416010818cSAlexey Kardashevskiy             node_size -= sizetmp;
5426010818cSAlexey Kardashevskiy             mem_start += sizetmp;
5436010818cSAlexey Kardashevskiy         }
54453018216SPaolo Bonzini     }
54553018216SPaolo Bonzini 
54653018216SPaolo Bonzini     return 0;
54753018216SPaolo Bonzini }
54853018216SPaolo Bonzini 
5490da6f3feSBharata B Rao static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
5500da6f3feSBharata B Rao                                   sPAPRMachineState *spapr)
5510da6f3feSBharata B Rao {
5520da6f3feSBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
5530da6f3feSBharata B Rao     CPUPPCState *env = &cpu->env;
5540da6f3feSBharata B Rao     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
5550da6f3feSBharata B Rao     int index = ppc_get_vcpu_dt_id(cpu);
5560da6f3feSBharata B Rao     uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
5570da6f3feSBharata B Rao                        0xffffffff, 0xffffffff};
558afd10a0fSBharata B Rao     uint32_t tbfreq = kvm_enabled() ? kvmppc_get_tbfreq()
559afd10a0fSBharata B Rao         : SPAPR_TIMEBASE_FREQ;
5600da6f3feSBharata B Rao     uint32_t cpufreq = kvm_enabled() ? kvmppc_get_clockfreq() : 1000000000;
5610da6f3feSBharata B Rao     uint32_t page_sizes_prop[64];
5620da6f3feSBharata B Rao     size_t page_sizes_prop_size;
56322419c2aSDavid Gibson     uint32_t vcpus_per_socket = smp_threads * smp_cores;
5640da6f3feSBharata B Rao     uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
565af81cf32SBharata B Rao     sPAPRDRConnector *drc;
566af81cf32SBharata B Rao     sPAPRDRConnectorClass *drck;
567af81cf32SBharata B Rao     int drc_index;
568af81cf32SBharata B Rao 
569af81cf32SBharata B Rao     drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_CPU, index);
570af81cf32SBharata B Rao     if (drc) {
571af81cf32SBharata B Rao         drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
572af81cf32SBharata B Rao         drc_index = drck->get_index(drc);
573af81cf32SBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,my-drc-index", drc_index)));
574af81cf32SBharata B Rao     }
5750da6f3feSBharata B Rao 
57690da0d5aSBenjamin Herrenschmidt     /* Note: we keep CI large pages off for now because a 64K capable guest
57790da0d5aSBenjamin Herrenschmidt      * provisioned with large pages might otherwise try to map a qemu
57890da0d5aSBenjamin Herrenschmidt      * framebuffer (or other kind of memory mapped PCI BAR) using 64K pages
57990da0d5aSBenjamin Herrenschmidt      * even if that qemu runs on a 4k host.
58090da0d5aSBenjamin Herrenschmidt      *
58190da0d5aSBenjamin Herrenschmidt      * We can later add this bit back when we are confident this is not
58290da0d5aSBenjamin Herrenschmidt      * an issue (!HV KVM or 64K host)
58390da0d5aSBenjamin Herrenschmidt      */
58490da0d5aSBenjamin Herrenschmidt     uint8_t pa_features_206[] = { 6, 0,
58590da0d5aSBenjamin Herrenschmidt         0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
58690da0d5aSBenjamin Herrenschmidt     uint8_t pa_features_207[] = { 24, 0,
58790da0d5aSBenjamin Herrenschmidt         0xf6, 0x1f, 0xc7, 0xc0, 0x80, 0xf0,
58890da0d5aSBenjamin Herrenschmidt         0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
58990da0d5aSBenjamin Herrenschmidt         0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
59090da0d5aSBenjamin Herrenschmidt         0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
59190da0d5aSBenjamin Herrenschmidt     uint8_t *pa_features;
59290da0d5aSBenjamin Herrenschmidt     size_t pa_size;
59390da0d5aSBenjamin Herrenschmidt 
5940da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "reg", index)));
5950da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "device_type", "cpu")));
5960da6f3feSBharata B Rao 
5970da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "cpu-version", env->spr[SPR_PVR])));
5980da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-block-size",
5990da6f3feSBharata B Rao                            env->dcache_line_size)));
6000da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "d-cache-line-size",
6010da6f3feSBharata B Rao                            env->dcache_line_size)));
6020da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-block-size",
6030da6f3feSBharata B Rao                            env->icache_line_size)));
6040da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "i-cache-line-size",
6050da6f3feSBharata B Rao                            env->icache_line_size)));
6060da6f3feSBharata B Rao 
6070da6f3feSBharata B Rao     if (pcc->l1_dcache_size) {
6080da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
6090da6f3feSBharata B Rao                                pcc->l1_dcache_size)));
6100da6f3feSBharata B Rao     } else {
611ce9863b7SCédric Le Goater         error_report("Warning: Unknown L1 dcache size for cpu");
6120da6f3feSBharata B Rao     }
6130da6f3feSBharata B Rao     if (pcc->l1_icache_size) {
6140da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
6150da6f3feSBharata B Rao                                pcc->l1_icache_size)));
6160da6f3feSBharata B Rao     } else {
617ce9863b7SCédric Le Goater         error_report("Warning: Unknown L1 icache size for cpu");
6180da6f3feSBharata B Rao     }
6190da6f3feSBharata B Rao 
6200da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
6210da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
622fd5da5c4SThomas Huth     _FDT((fdt_setprop_cell(fdt, offset, "slb-size", env->slb_nr)));
6230da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", env->slb_nr)));
6240da6f3feSBharata B Rao     _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
6250da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
6260da6f3feSBharata B Rao 
6270da6f3feSBharata B Rao     if (env->spr_cb[SPR_PURR].oea_read) {
6280da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,purr", NULL, 0)));
6290da6f3feSBharata B Rao     }
6300da6f3feSBharata B Rao 
6310da6f3feSBharata B Rao     if (env->mmu_model & POWERPC_MMU_1TSEG) {
6320da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,processor-segment-sizes",
6330da6f3feSBharata B Rao                           segs, sizeof(segs))));
6340da6f3feSBharata B Rao     }
6350da6f3feSBharata B Rao 
6360da6f3feSBharata B Rao     /* Advertise VMX/VSX (vector extensions) if available
6370da6f3feSBharata B Rao      *   0 / no property == no vector extensions
6380da6f3feSBharata B Rao      *   1               == VMX / Altivec available
6390da6f3feSBharata B Rao      *   2               == VSX available */
6400da6f3feSBharata B Rao     if (env->insns_flags & PPC_ALTIVEC) {
6410da6f3feSBharata B Rao         uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
6420da6f3feSBharata B Rao 
6430da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
6440da6f3feSBharata B Rao     }
6450da6f3feSBharata B Rao 
6460da6f3feSBharata B Rao     /* Advertise DFP (Decimal Floating Point) if available
6470da6f3feSBharata B Rao      *   0 / no property == no DFP
6480da6f3feSBharata B Rao      *   1               == DFP available */
6490da6f3feSBharata B Rao     if (env->insns_flags2 & PPC2_DFP) {
6500da6f3feSBharata B Rao         _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
6510da6f3feSBharata B Rao     }
6520da6f3feSBharata B Rao 
6533654fa95SCédric Le Goater     page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
6540da6f3feSBharata B Rao                                                   sizeof(page_sizes_prop));
6550da6f3feSBharata B Rao     if (page_sizes_prop_size) {
6560da6f3feSBharata B Rao         _FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
6570da6f3feSBharata B Rao                           page_sizes_prop, page_sizes_prop_size)));
6580da6f3feSBharata B Rao     }
6590da6f3feSBharata B Rao 
66090da0d5aSBenjamin Herrenschmidt     /* Do the ibm,pa-features property, adjust it for ci-large-pages */
66190da0d5aSBenjamin Herrenschmidt     if (env->mmu_model == POWERPC_MMU_2_06) {
66290da0d5aSBenjamin Herrenschmidt         pa_features = pa_features_206;
66390da0d5aSBenjamin Herrenschmidt         pa_size = sizeof(pa_features_206);
66490da0d5aSBenjamin Herrenschmidt     } else /* env->mmu_model == POWERPC_MMU_2_07 */ {
66590da0d5aSBenjamin Herrenschmidt         pa_features = pa_features_207;
66690da0d5aSBenjamin Herrenschmidt         pa_size = sizeof(pa_features_207);
66790da0d5aSBenjamin Herrenschmidt     }
66890da0d5aSBenjamin Herrenschmidt     if (env->ci_large_pages) {
66990da0d5aSBenjamin Herrenschmidt         pa_features[3] |= 0x20;
67090da0d5aSBenjamin Herrenschmidt     }
67190da0d5aSBenjamin Herrenschmidt     _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
67290da0d5aSBenjamin Herrenschmidt 
6730da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
67422419c2aSDavid Gibson                            cs->cpu_index / vcpus_per_socket)));
6750da6f3feSBharata B Rao 
6760da6f3feSBharata B Rao     _FDT((fdt_setprop(fdt, offset, "ibm,pft-size",
6770da6f3feSBharata B Rao                       pft_size_prop, sizeof(pft_size_prop))));
6780da6f3feSBharata B Rao 
6790da6f3feSBharata B Rao     _FDT(spapr_fixup_cpu_numa_dt(fdt, offset, cs));
6800da6f3feSBharata B Rao 
6810da6f3feSBharata B Rao     _FDT(spapr_fixup_cpu_smt_dt(fdt, offset, cpu,
6820da6f3feSBharata B Rao                                 ppc_get_compat_smt_threads(cpu)));
6830da6f3feSBharata B Rao }
6840da6f3feSBharata B Rao 
6850da6f3feSBharata B Rao static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr)
6860da6f3feSBharata B Rao {
6870da6f3feSBharata B Rao     CPUState *cs;
6880da6f3feSBharata B Rao     int cpus_offset;
6890da6f3feSBharata B Rao     char *nodename;
6900da6f3feSBharata B Rao     int smt = kvmppc_smt_threads();
6910da6f3feSBharata B Rao 
6920da6f3feSBharata B Rao     cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
6930da6f3feSBharata B Rao     _FDT(cpus_offset);
6940da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#address-cells", 0x1)));
6950da6f3feSBharata B Rao     _FDT((fdt_setprop_cell(fdt, cpus_offset, "#size-cells", 0x0)));
6960da6f3feSBharata B Rao 
6970da6f3feSBharata B Rao     /*
6980da6f3feSBharata B Rao      * We walk the CPUs in reverse order to ensure that CPU DT nodes
6990da6f3feSBharata B Rao      * created by fdt_add_subnode() end up in the right order in FDT
7000da6f3feSBharata B Rao      * for the guest kernel the enumerate the CPUs correctly.
7010da6f3feSBharata B Rao      */
7020da6f3feSBharata B Rao     CPU_FOREACH_REVERSE(cs) {
7030da6f3feSBharata B Rao         PowerPCCPU *cpu = POWERPC_CPU(cs);
7040da6f3feSBharata B Rao         int index = ppc_get_vcpu_dt_id(cpu);
7050da6f3feSBharata B Rao         DeviceClass *dc = DEVICE_GET_CLASS(cs);
7060da6f3feSBharata B Rao         int offset;
7070da6f3feSBharata B Rao 
7080da6f3feSBharata B Rao         if ((index % smt) != 0) {
7090da6f3feSBharata B Rao             continue;
7100da6f3feSBharata B Rao         }
7110da6f3feSBharata B Rao 
7120da6f3feSBharata B Rao         nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
7130da6f3feSBharata B Rao         offset = fdt_add_subnode(fdt, cpus_offset, nodename);
7140da6f3feSBharata B Rao         g_free(nodename);
7150da6f3feSBharata B Rao         _FDT(offset);
7160da6f3feSBharata B Rao         spapr_populate_cpu_dt(cs, fdt, offset, spapr);
7170da6f3feSBharata B Rao     }
7180da6f3feSBharata B Rao 
7190da6f3feSBharata B Rao }
7200da6f3feSBharata B Rao 
72103d196b7SBharata B Rao /*
72203d196b7SBharata B Rao  * Adds ibm,dynamic-reconfiguration-memory node.
72303d196b7SBharata B Rao  * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation
72403d196b7SBharata B Rao  * of this device tree node.
72503d196b7SBharata B Rao  */
72603d196b7SBharata B Rao static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt)
72703d196b7SBharata B Rao {
72803d196b7SBharata B Rao     MachineState *machine = MACHINE(spapr);
72903d196b7SBharata B Rao     int ret, i, offset;
73003d196b7SBharata B Rao     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
73103d196b7SBharata B Rao     uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
732d0e5a8f2SBharata B Rao     uint32_t hotplug_lmb_start = spapr->hotplug_memory.base / lmb_size;
733d0e5a8f2SBharata B Rao     uint32_t nr_lmbs = (spapr->hotplug_memory.base +
734d0e5a8f2SBharata B Rao                        memory_region_size(&spapr->hotplug_memory.mr)) /
735d0e5a8f2SBharata B Rao                        lmb_size;
73603d196b7SBharata B Rao     uint32_t *int_buf, *cur_index, buf_len;
7376663864eSBharata B Rao     int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
73803d196b7SBharata B Rao 
739ef001f06SThomas Huth     /*
740d0e5a8f2SBharata B Rao      * Don't create the node if there is no hotpluggable memory
74116c25aefSBharata B Rao      */
742d0e5a8f2SBharata B Rao     if (machine->ram_size == machine->maxram_size) {
74316c25aefSBharata B Rao         return 0;
74416c25aefSBharata B Rao     }
74516c25aefSBharata B Rao 
74616c25aefSBharata B Rao     /*
747ef001f06SThomas Huth      * Allocate enough buffer size to fit in ibm,dynamic-memory
748ef001f06SThomas Huth      * or ibm,associativity-lookup-arrays
749ef001f06SThomas Huth      */
750ef001f06SThomas Huth     buf_len = MAX(nr_lmbs * SPAPR_DR_LMB_LIST_ENTRY_SIZE + 1, nr_nodes * 4 + 2)
751ef001f06SThomas Huth               * sizeof(uint32_t);
75203d196b7SBharata B Rao     cur_index = int_buf = g_malloc0(buf_len);
75303d196b7SBharata B Rao 
75403d196b7SBharata B Rao     offset = fdt_add_subnode(fdt, 0, "ibm,dynamic-reconfiguration-memory");
75503d196b7SBharata B Rao 
75603d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,lmb-size", prop_lmb_size,
75703d196b7SBharata B Rao                     sizeof(prop_lmb_size));
75803d196b7SBharata B Rao     if (ret < 0) {
75903d196b7SBharata B Rao         goto out;
76003d196b7SBharata B Rao     }
76103d196b7SBharata B Rao 
76203d196b7SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-flags-mask", 0xff);
76303d196b7SBharata B Rao     if (ret < 0) {
76403d196b7SBharata B Rao         goto out;
76503d196b7SBharata B Rao     }
76603d196b7SBharata B Rao 
76703d196b7SBharata B Rao     ret = fdt_setprop_cell(fdt, offset, "ibm,memory-preservation-time", 0x0);
76803d196b7SBharata B Rao     if (ret < 0) {
76903d196b7SBharata B Rao         goto out;
77003d196b7SBharata B Rao     }
77103d196b7SBharata B Rao 
77203d196b7SBharata B Rao     /* ibm,dynamic-memory */
77303d196b7SBharata B Rao     int_buf[0] = cpu_to_be32(nr_lmbs);
77403d196b7SBharata B Rao     cur_index++;
77503d196b7SBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
776d0e5a8f2SBharata B Rao         uint64_t addr = i * lmb_size;
77703d196b7SBharata B Rao         uint32_t *dynamic_memory = cur_index;
77803d196b7SBharata B Rao 
779d0e5a8f2SBharata B Rao         if (i >= hotplug_lmb_start) {
780d0e5a8f2SBharata B Rao             sPAPRDRConnector *drc;
781d0e5a8f2SBharata B Rao             sPAPRDRConnectorClass *drck;
782d0e5a8f2SBharata B Rao 
783d0e5a8f2SBharata B Rao             drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, i);
78403d196b7SBharata B Rao             g_assert(drc);
78503d196b7SBharata B Rao             drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
78603d196b7SBharata B Rao 
78703d196b7SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
78803d196b7SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
78903d196b7SBharata B Rao             dynamic_memory[2] = cpu_to_be32(drck->get_index(drc));
79003d196b7SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
79103d196b7SBharata B Rao             dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
792d0e5a8f2SBharata B Rao             if (memory_region_present(get_system_memory(), addr)) {
79303d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
79403d196b7SBharata B Rao             } else {
79503d196b7SBharata B Rao                 dynamic_memory[5] = cpu_to_be32(0);
79603d196b7SBharata B Rao             }
797d0e5a8f2SBharata B Rao         } else {
798d0e5a8f2SBharata B Rao             /*
799d0e5a8f2SBharata B Rao              * LMB information for RMA, boot time RAM and gap b/n RAM and
800d0e5a8f2SBharata B Rao              * hotplug memory region -- all these are marked as reserved
801d0e5a8f2SBharata B Rao              * and as having no valid DRC.
802d0e5a8f2SBharata B Rao              */
803d0e5a8f2SBharata B Rao             dynamic_memory[0] = cpu_to_be32(addr >> 32);
804d0e5a8f2SBharata B Rao             dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
805d0e5a8f2SBharata B Rao             dynamic_memory[2] = cpu_to_be32(0);
806d0e5a8f2SBharata B Rao             dynamic_memory[3] = cpu_to_be32(0); /* reserved */
807d0e5a8f2SBharata B Rao             dynamic_memory[4] = cpu_to_be32(-1);
808d0e5a8f2SBharata B Rao             dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
809d0e5a8f2SBharata B Rao                                             SPAPR_LMB_FLAGS_DRC_INVALID);
810d0e5a8f2SBharata B Rao         }
81103d196b7SBharata B Rao 
81203d196b7SBharata B Rao         cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
81303d196b7SBharata B Rao     }
81403d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len);
81503d196b7SBharata B Rao     if (ret < 0) {
81603d196b7SBharata B Rao         goto out;
81703d196b7SBharata B Rao     }
81803d196b7SBharata B Rao 
81903d196b7SBharata B Rao     /* ibm,associativity-lookup-arrays */
82003d196b7SBharata B Rao     cur_index = int_buf;
8216663864eSBharata B Rao     int_buf[0] = cpu_to_be32(nr_nodes);
82203d196b7SBharata B Rao     int_buf[1] = cpu_to_be32(4); /* Number of entries per associativity list */
82303d196b7SBharata B Rao     cur_index += 2;
8246663864eSBharata B Rao     for (i = 0; i < nr_nodes; i++) {
82503d196b7SBharata B Rao         uint32_t associativity[] = {
82603d196b7SBharata B Rao             cpu_to_be32(0x0),
82703d196b7SBharata B Rao             cpu_to_be32(0x0),
82803d196b7SBharata B Rao             cpu_to_be32(0x0),
82903d196b7SBharata B Rao             cpu_to_be32(i)
83003d196b7SBharata B Rao         };
83103d196b7SBharata B Rao         memcpy(cur_index, associativity, sizeof(associativity));
83203d196b7SBharata B Rao         cur_index += 4;
83303d196b7SBharata B Rao     }
83403d196b7SBharata B Rao     ret = fdt_setprop(fdt, offset, "ibm,associativity-lookup-arrays", int_buf,
83503d196b7SBharata B Rao             (cur_index - int_buf) * sizeof(uint32_t));
83603d196b7SBharata B Rao out:
83703d196b7SBharata B Rao     g_free(int_buf);
83803d196b7SBharata B Rao     return ret;
83903d196b7SBharata B Rao }
84003d196b7SBharata B Rao 
84103d196b7SBharata B Rao int spapr_h_cas_compose_response(sPAPRMachineState *spapr,
84203d196b7SBharata B Rao                                  target_ulong addr, target_ulong size,
84303d196b7SBharata B Rao                                  bool cpu_update, bool memory_update)
84403d196b7SBharata B Rao {
84503d196b7SBharata B Rao     void *fdt, *fdt_skel;
84603d196b7SBharata B Rao     sPAPRDeviceTreeUpdateHeader hdr = { .version_id = 1 };
84703d196b7SBharata B Rao     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
84803d196b7SBharata B Rao 
84903d196b7SBharata B Rao     size -= sizeof(hdr);
85003d196b7SBharata B Rao 
85103d196b7SBharata B Rao     /* Create sceleton */
85203d196b7SBharata B Rao     fdt_skel = g_malloc0(size);
85303d196b7SBharata B Rao     _FDT((fdt_create(fdt_skel, size)));
85403d196b7SBharata B Rao     _FDT((fdt_begin_node(fdt_skel, "")));
85503d196b7SBharata B Rao     _FDT((fdt_end_node(fdt_skel)));
85603d196b7SBharata B Rao     _FDT((fdt_finish(fdt_skel)));
85703d196b7SBharata B Rao     fdt = g_malloc0(size);
85803d196b7SBharata B Rao     _FDT((fdt_open_into(fdt_skel, fdt, size)));
85903d196b7SBharata B Rao     g_free(fdt_skel);
86003d196b7SBharata B Rao 
86103d196b7SBharata B Rao     /* Fixup cpu nodes */
86203d196b7SBharata B Rao     if (cpu_update) {
86303d196b7SBharata B Rao         _FDT((spapr_fixup_cpu_dt(fdt, spapr)));
86403d196b7SBharata B Rao     }
86503d196b7SBharata B Rao 
86616c25aefSBharata B Rao     /* Generate ibm,dynamic-reconfiguration-memory node if required */
86703d196b7SBharata B Rao     if (memory_update && smc->dr_lmb_enabled) {
86803d196b7SBharata B Rao         _FDT((spapr_populate_drconf_memory(spapr, fdt)));
86903d196b7SBharata B Rao     }
87003d196b7SBharata B Rao 
87103d196b7SBharata B Rao     /* Pack resulting tree */
87203d196b7SBharata B Rao     _FDT((fdt_pack(fdt)));
87303d196b7SBharata B Rao 
87403d196b7SBharata B Rao     if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
87503d196b7SBharata B Rao         trace_spapr_cas_failed(size);
87603d196b7SBharata B Rao         return -1;
87703d196b7SBharata B Rao     }
87803d196b7SBharata B Rao 
87903d196b7SBharata B Rao     cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
88003d196b7SBharata B Rao     cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
88103d196b7SBharata B Rao     trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
88203d196b7SBharata B Rao     g_free(fdt);
88303d196b7SBharata B Rao 
88403d196b7SBharata B Rao     return 0;
88503d196b7SBharata B Rao }
88603d196b7SBharata B Rao 
88728e02042SDavid Gibson static void spapr_finalize_fdt(sPAPRMachineState *spapr,
88853018216SPaolo Bonzini                                hwaddr fdt_addr,
88953018216SPaolo Bonzini                                hwaddr rtas_addr,
89053018216SPaolo Bonzini                                hwaddr rtas_size)
89153018216SPaolo Bonzini {
8925b2128d2SAlexander Graf     MachineState *machine = MACHINE(qdev_get_machine());
8933c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
894c20d332aSBharata B Rao     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
8955b2128d2SAlexander Graf     const char *boot_device = machine->boot_order;
89671461b0fSAlexey Kardashevskiy     int ret, i;
89771461b0fSAlexey Kardashevskiy     size_t cb = 0;
89871461b0fSAlexey Kardashevskiy     char *bootlist;
89953018216SPaolo Bonzini     void *fdt;
90053018216SPaolo Bonzini     sPAPRPHBState *phb;
90153018216SPaolo Bonzini 
90253018216SPaolo Bonzini     fdt = g_malloc(FDT_MAX_SIZE);
90353018216SPaolo Bonzini 
90453018216SPaolo Bonzini     /* open out the base tree into a temp buffer for the final tweaks */
90553018216SPaolo Bonzini     _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE)));
90653018216SPaolo Bonzini 
907e8f986fcSBharata B Rao     ret = spapr_populate_memory(spapr, fdt);
908e8f986fcSBharata B Rao     if (ret < 0) {
909ce9863b7SCédric Le Goater         error_report("couldn't setup memory nodes in fdt");
910e8f986fcSBharata B Rao         exit(1);
91153018216SPaolo Bonzini     }
91253018216SPaolo Bonzini 
91353018216SPaolo Bonzini     ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
91453018216SPaolo Bonzini     if (ret < 0) {
915ce9863b7SCédric Le Goater         error_report("couldn't setup vio devices in fdt");
91653018216SPaolo Bonzini         exit(1);
91753018216SPaolo Bonzini     }
91853018216SPaolo Bonzini 
9194d9392beSThomas Huth     if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
9204d9392beSThomas Huth         ret = spapr_rng_populate_dt(fdt);
9214d9392beSThomas Huth         if (ret < 0) {
922ce9863b7SCédric Le Goater             error_report("could not set up rng device in the fdt");
9234d9392beSThomas Huth             exit(1);
9244d9392beSThomas Huth         }
9254d9392beSThomas Huth     }
9264d9392beSThomas Huth 
92753018216SPaolo Bonzini     QLIST_FOREACH(phb, &spapr->phbs, list) {
92853018216SPaolo Bonzini         ret = spapr_populate_pci_dt(phb, PHANDLE_XICP, fdt);
92953018216SPaolo Bonzini         if (ret < 0) {
930da34fed7SThomas Huth             error_report("couldn't setup PCI devices in fdt");
93153018216SPaolo Bonzini             exit(1);
93253018216SPaolo Bonzini         }
933da34fed7SThomas Huth     }
93453018216SPaolo Bonzini 
93553018216SPaolo Bonzini     /* RTAS */
93653018216SPaolo Bonzini     ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
93753018216SPaolo Bonzini     if (ret < 0) {
938ce9863b7SCédric Le Goater         error_report("Couldn't set up RTAS device tree properties");
93953018216SPaolo Bonzini     }
94053018216SPaolo Bonzini 
9410da6f3feSBharata B Rao     /* cpus */
9420da6f3feSBharata B Rao     spapr_populate_cpus_dt_node(fdt, spapr);
94353018216SPaolo Bonzini 
94471461b0fSAlexey Kardashevskiy     bootlist = get_boot_devices_list(&cb, true);
94571461b0fSAlexey Kardashevskiy     if (cb && bootlist) {
94671461b0fSAlexey Kardashevskiy         int offset = fdt_path_offset(fdt, "/chosen");
94771461b0fSAlexey Kardashevskiy         if (offset < 0) {
94871461b0fSAlexey Kardashevskiy             exit(1);
94971461b0fSAlexey Kardashevskiy         }
95071461b0fSAlexey Kardashevskiy         for (i = 0; i < cb; i++) {
95171461b0fSAlexey Kardashevskiy             if (bootlist[i] == '\n') {
95271461b0fSAlexey Kardashevskiy                 bootlist[i] = ' ';
95371461b0fSAlexey Kardashevskiy             }
95471461b0fSAlexey Kardashevskiy 
95571461b0fSAlexey Kardashevskiy         }
95671461b0fSAlexey Kardashevskiy         ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist);
95771461b0fSAlexey Kardashevskiy     }
95871461b0fSAlexey Kardashevskiy 
9595b2128d2SAlexander Graf     if (boot_device && strlen(boot_device)) {
9605b2128d2SAlexander Graf         int offset = fdt_path_offset(fdt, "/chosen");
9615b2128d2SAlexander Graf 
9625b2128d2SAlexander Graf         if (offset < 0) {
9635b2128d2SAlexander Graf             exit(1);
9645b2128d2SAlexander Graf         }
9655b2128d2SAlexander Graf         fdt_setprop_string(fdt, offset, "qemu,boot-device", boot_device);
9665b2128d2SAlexander Graf     }
9675b2128d2SAlexander Graf 
96853018216SPaolo Bonzini     if (!spapr->has_graphics) {
96953018216SPaolo Bonzini         spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
97053018216SPaolo Bonzini     }
97153018216SPaolo Bonzini 
972c20d332aSBharata B Rao     if (smc->dr_lmb_enabled) {
973c20d332aSBharata B Rao         _FDT(spapr_drc_populate_dt(fdt, 0, NULL, SPAPR_DR_CONNECTOR_TYPE_LMB));
974c20d332aSBharata B Rao     }
975c20d332aSBharata B Rao 
9763c0c47e3SDavid Gibson     if (mc->query_hotpluggable_cpus) {
977af81cf32SBharata B Rao         int offset = fdt_path_offset(fdt, "/cpus");
978af81cf32SBharata B Rao         ret = spapr_drc_populate_dt(fdt, offset, NULL,
979af81cf32SBharata B Rao                                     SPAPR_DR_CONNECTOR_TYPE_CPU);
980af81cf32SBharata B Rao         if (ret < 0) {
981af81cf32SBharata B Rao             error_report("Couldn't set up CPU DR device tree properties");
982af81cf32SBharata B Rao             exit(1);
983af81cf32SBharata B Rao         }
984af81cf32SBharata B Rao     }
985af81cf32SBharata B Rao 
98653018216SPaolo Bonzini     _FDT((fdt_pack(fdt)));
98753018216SPaolo Bonzini 
98853018216SPaolo Bonzini     if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
989730fce59SThomas Huth         error_report("FDT too big ! 0x%x bytes (max is 0x%x)",
99053018216SPaolo Bonzini                      fdt_totalsize(fdt), FDT_MAX_SIZE);
99153018216SPaolo Bonzini         exit(1);
99253018216SPaolo Bonzini     }
99353018216SPaolo Bonzini 
994ad440b4aSAndrew Jones     qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
99553018216SPaolo Bonzini     cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
99653018216SPaolo Bonzini 
997a21a7a70SGonglei     g_free(bootlist);
99853018216SPaolo Bonzini     g_free(fdt);
99953018216SPaolo Bonzini }
100053018216SPaolo Bonzini 
100153018216SPaolo Bonzini static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
100253018216SPaolo Bonzini {
100353018216SPaolo Bonzini     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
100453018216SPaolo Bonzini }
100553018216SPaolo Bonzini 
100653018216SPaolo Bonzini static void emulate_spapr_hypercall(PowerPCCPU *cpu)
100753018216SPaolo Bonzini {
100853018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
100953018216SPaolo Bonzini 
101053018216SPaolo Bonzini     if (msr_pr) {
101153018216SPaolo Bonzini         hcall_dprintf("Hypercall made with MSR[PR]=1\n");
101253018216SPaolo Bonzini         env->gpr[3] = H_PRIVILEGE;
101353018216SPaolo Bonzini     } else {
101453018216SPaolo Bonzini         env->gpr[3] = spapr_hypercall(cpu, env->gpr[3], &env->gpr[4]);
101553018216SPaolo Bonzini     }
101653018216SPaolo Bonzini }
101753018216SPaolo Bonzini 
1018e6b8fd24SSamuel Mendoza-Jonas #define HPTE(_table, _i)   (void *)(((uint64_t *)(_table)) + ((_i) * 2))
1019e6b8fd24SSamuel Mendoza-Jonas #define HPTE_VALID(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
1020e6b8fd24SSamuel Mendoza-Jonas #define HPTE_DIRTY(_hpte)  (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
1021e6b8fd24SSamuel Mendoza-Jonas #define CLEAN_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
1022e6b8fd24SSamuel Mendoza-Jonas #define DIRTY_HPTE(_hpte)  ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
1023e6b8fd24SSamuel Mendoza-Jonas 
1024715c5407SDavid Gibson /*
1025715c5407SDavid Gibson  * Get the fd to access the kernel htab, re-opening it if necessary
1026715c5407SDavid Gibson  */
1027715c5407SDavid Gibson static int get_htab_fd(sPAPRMachineState *spapr)
1028715c5407SDavid Gibson {
1029715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1030715c5407SDavid Gibson         return spapr->htab_fd;
1031715c5407SDavid Gibson     }
1032715c5407SDavid Gibson 
1033715c5407SDavid Gibson     spapr->htab_fd = kvmppc_get_htab_fd(false);
1034715c5407SDavid Gibson     if (spapr->htab_fd < 0) {
1035715c5407SDavid Gibson         error_report("Unable to open fd for reading hash table from KVM: %s",
1036715c5407SDavid Gibson                      strerror(errno));
1037715c5407SDavid Gibson     }
1038715c5407SDavid Gibson 
1039715c5407SDavid Gibson     return spapr->htab_fd;
1040715c5407SDavid Gibson }
1041715c5407SDavid Gibson 
1042715c5407SDavid Gibson static void close_htab_fd(sPAPRMachineState *spapr)
1043715c5407SDavid Gibson {
1044715c5407SDavid Gibson     if (spapr->htab_fd >= 0) {
1045715c5407SDavid Gibson         close(spapr->htab_fd);
1046715c5407SDavid Gibson     }
1047715c5407SDavid Gibson     spapr->htab_fd = -1;
1048715c5407SDavid Gibson }
1049715c5407SDavid Gibson 
10508dfe8e7fSDavid Gibson static int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
10518dfe8e7fSDavid Gibson {
10528dfe8e7fSDavid Gibson     int shift;
10538dfe8e7fSDavid Gibson 
10548dfe8e7fSDavid Gibson     /* We aim for a hash table of size 1/128 the size of RAM (rounded
10558dfe8e7fSDavid Gibson      * up).  The PAPR recommendation is actually 1/64 of RAM size, but
10568dfe8e7fSDavid Gibson      * that's much more than is needed for Linux guests */
10578dfe8e7fSDavid Gibson     shift = ctz64(pow2ceil(ramsize)) - 7;
10588dfe8e7fSDavid Gibson     shift = MAX(shift, 18); /* Minimum architected size */
10598dfe8e7fSDavid Gibson     shift = MIN(shift, 46); /* Maximum architected size */
10608dfe8e7fSDavid Gibson     return shift;
10618dfe8e7fSDavid Gibson }
10628dfe8e7fSDavid Gibson 
1063c5f54f3eSDavid Gibson static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift,
1064c5f54f3eSDavid Gibson                                  Error **errp)
106553018216SPaolo Bonzini {
1066c5f54f3eSDavid Gibson     long rc;
106753018216SPaolo Bonzini 
1068c5f54f3eSDavid Gibson     /* Clean up any HPT info from a previous boot */
1069c5f54f3eSDavid Gibson     g_free(spapr->htab);
1070c5f54f3eSDavid Gibson     spapr->htab = NULL;
1071c5f54f3eSDavid Gibson     spapr->htab_shift = 0;
1072c5f54f3eSDavid Gibson     close_htab_fd(spapr);
107353018216SPaolo Bonzini 
1074c5f54f3eSDavid Gibson     rc = kvmppc_reset_htab(shift);
1075c5f54f3eSDavid Gibson     if (rc < 0) {
1076c5f54f3eSDavid Gibson         /* kernel-side HPT needed, but couldn't allocate one */
1077c5f54f3eSDavid Gibson         error_setg_errno(errp, errno,
1078c5f54f3eSDavid Gibson                          "Failed to allocate KVM HPT of order %d (try smaller maxmem?)",
1079c5f54f3eSDavid Gibson                          shift);
1080c5f54f3eSDavid Gibson         /* This is almost certainly fatal, but if the caller really
1081c5f54f3eSDavid Gibson          * wants to carry on with shift == 0, it's welcome to try */
1082c5f54f3eSDavid Gibson     } else if (rc > 0) {
1083c5f54f3eSDavid Gibson         /* kernel-side HPT allocated */
1084c5f54f3eSDavid Gibson         if (rc != shift) {
1085c5f54f3eSDavid Gibson             error_setg(errp,
1086c5f54f3eSDavid Gibson                        "Requested order %d HPT, but kernel allocated order %ld (try smaller maxmem?)",
1087c5f54f3eSDavid Gibson                        shift, rc);
10887735fedaSBharata B Rao         }
10897735fedaSBharata B Rao 
109053018216SPaolo Bonzini         spapr->htab_shift = shift;
1091c18ad9a5SDavid Gibson         spapr->htab = NULL;
1092b817772aSBharata B Rao     } else {
1093c5f54f3eSDavid Gibson         /* kernel-side HPT not needed, allocate in userspace instead */
1094c5f54f3eSDavid Gibson         size_t size = 1ULL << shift;
1095c5f54f3eSDavid Gibson         int i;
109601a57972SSamuel Mendoza-Jonas 
1097c5f54f3eSDavid Gibson         spapr->htab = qemu_memalign(size, size);
1098c5f54f3eSDavid Gibson         if (!spapr->htab) {
1099c5f54f3eSDavid Gibson             error_setg_errno(errp, errno,
1100c5f54f3eSDavid Gibson                              "Could not allocate HPT of order %d", shift);
1101c5f54f3eSDavid Gibson             return;
1102b817772aSBharata B Rao         }
1103b817772aSBharata B Rao 
1104c5f54f3eSDavid Gibson         memset(spapr->htab, 0, size);
1105c5f54f3eSDavid Gibson         spapr->htab_shift = shift;
1106b817772aSBharata B Rao 
1107c5f54f3eSDavid Gibson         for (i = 0; i < size / HASH_PTE_SIZE_64; i++) {
1108c5f54f3eSDavid Gibson             DIRTY_HPTE(HPTE(spapr->htab, i));
11097735fedaSBharata B Rao         }
111053018216SPaolo Bonzini     }
111153018216SPaolo Bonzini }
111253018216SPaolo Bonzini 
11139e3f9733SAlexander Graf static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
11149e3f9733SAlexander Graf {
11159e3f9733SAlexander Graf     bool matched = false;
11169e3f9733SAlexander Graf 
11179e3f9733SAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
11189e3f9733SAlexander Graf         matched = true;
11199e3f9733SAlexander Graf     }
11209e3f9733SAlexander Graf 
11219e3f9733SAlexander Graf     if (!matched) {
11229e3f9733SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
11239e3f9733SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
11249e3f9733SAlexander Graf         exit(1);
11259e3f9733SAlexander Graf     }
11269e3f9733SAlexander Graf 
11279e3f9733SAlexander Graf     return 0;
11289e3f9733SAlexander Graf }
11299e3f9733SAlexander Graf 
113053018216SPaolo Bonzini static void ppc_spapr_reset(void)
113153018216SPaolo Bonzini {
1132c5f54f3eSDavid Gibson     MachineState *machine = MACHINE(qdev_get_machine());
1133c5f54f3eSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
1134182735efSAndreas Färber     PowerPCCPU *first_ppc_cpu;
1135b7d1f77aSBenjamin Herrenschmidt     uint32_t rtas_limit;
1136259186a7SAndreas Färber 
11379e3f9733SAlexander Graf     /* Check for unknown sysbus devices */
11389e3f9733SAlexander Graf     foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
11399e3f9733SAlexander Graf 
1140c5f54f3eSDavid Gibson     /* Allocate and/or reset the hash page table */
1141c5f54f3eSDavid Gibson     spapr_reallocate_hpt(spapr,
1142c5f54f3eSDavid Gibson                          spapr_hpt_shift_for_ramsize(machine->maxram_size),
1143c5f54f3eSDavid Gibson                          &error_fatal);
1144c5f54f3eSDavid Gibson 
1145c5f54f3eSDavid Gibson     /* Update the RMA size if necessary */
1146c5f54f3eSDavid Gibson     if (spapr->vrma_adjust) {
1147c5f54f3eSDavid Gibson         spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
1148c5f54f3eSDavid Gibson                                           spapr->htab_shift);
1149c5f54f3eSDavid Gibson     }
115053018216SPaolo Bonzini 
115153018216SPaolo Bonzini     qemu_devices_reset();
115253018216SPaolo Bonzini 
1153b7d1f77aSBenjamin Herrenschmidt     /*
1154b7d1f77aSBenjamin Herrenschmidt      * We place the device tree and RTAS just below either the top of the RMA,
1155b7d1f77aSBenjamin Herrenschmidt      * or just below 2GB, whichever is lowere, so that it can be
1156b7d1f77aSBenjamin Herrenschmidt      * processed with 32-bit real mode code if necessary
1157b7d1f77aSBenjamin Herrenschmidt      */
1158b7d1f77aSBenjamin Herrenschmidt     rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
1159b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
1160b7d1f77aSBenjamin Herrenschmidt     spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
1161b7d1f77aSBenjamin Herrenschmidt 
116253018216SPaolo Bonzini     /* Load the fdt */
116353018216SPaolo Bonzini     spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
116453018216SPaolo Bonzini                        spapr->rtas_size);
116553018216SPaolo Bonzini 
1166b7d1f77aSBenjamin Herrenschmidt     /* Copy RTAS over */
1167b7d1f77aSBenjamin Herrenschmidt     cpu_physical_memory_write(spapr->rtas_addr, spapr->rtas_blob,
1168b7d1f77aSBenjamin Herrenschmidt                               spapr->rtas_size);
1169b7d1f77aSBenjamin Herrenschmidt 
117053018216SPaolo Bonzini     /* Set up the entry state */
1171182735efSAndreas Färber     first_ppc_cpu = POWERPC_CPU(first_cpu);
1172182735efSAndreas Färber     first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
1173182735efSAndreas Färber     first_ppc_cpu->env.gpr[5] = 0;
1174182735efSAndreas Färber     first_cpu->halted = 0;
11751b718907SDavid Gibson     first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT;
117653018216SPaolo Bonzini 
117753018216SPaolo Bonzini }
117853018216SPaolo Bonzini 
117928e02042SDavid Gibson static void spapr_create_nvram(sPAPRMachineState *spapr)
118053018216SPaolo Bonzini {
11812ff3de68SMarkus Armbruster     DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
11823978b863SPaolo Bonzini     DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
118353018216SPaolo Bonzini 
11843978b863SPaolo Bonzini     if (dinfo) {
11856231a6daSMarkus Armbruster         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
11866231a6daSMarkus Armbruster                             &error_fatal);
118753018216SPaolo Bonzini     }
118853018216SPaolo Bonzini 
118953018216SPaolo Bonzini     qdev_init_nofail(dev);
119053018216SPaolo Bonzini 
119153018216SPaolo Bonzini     spapr->nvram = (struct sPAPRNVRAM *)dev;
119253018216SPaolo Bonzini }
119353018216SPaolo Bonzini 
119428e02042SDavid Gibson static void spapr_rtc_create(sPAPRMachineState *spapr)
119528df36a1SDavid Gibson {
119628df36a1SDavid Gibson     DeviceState *dev = qdev_create(NULL, TYPE_SPAPR_RTC);
119728df36a1SDavid Gibson 
119828df36a1SDavid Gibson     qdev_init_nofail(dev);
119928df36a1SDavid Gibson     spapr->rtc = dev;
120074e5ae28SDavid Gibson 
120174e5ae28SDavid Gibson     object_property_add_alias(qdev_get_machine(), "rtc-time",
120274e5ae28SDavid Gibson                               OBJECT(spapr->rtc), "date", NULL);
120328df36a1SDavid Gibson }
120428df36a1SDavid Gibson 
120553018216SPaolo Bonzini /* Returns whether we want to use VGA or not */
120614c6a894SDavid Gibson static bool spapr_vga_init(PCIBus *pci_bus, Error **errp)
120753018216SPaolo Bonzini {
120853018216SPaolo Bonzini     switch (vga_interface_type) {
120953018216SPaolo Bonzini     case VGA_NONE:
12107effdaa3SMark Wu         return false;
12117effdaa3SMark Wu     case VGA_DEVICE:
12127effdaa3SMark Wu         return true;
121353018216SPaolo Bonzini     case VGA_STD:
1214b798c190SBenjamin Herrenschmidt     case VGA_VIRTIO:
121553018216SPaolo Bonzini         return pci_vga_init(pci_bus) != NULL;
121653018216SPaolo Bonzini     default:
121714c6a894SDavid Gibson         error_setg(errp,
121814c6a894SDavid Gibson                    "Unsupported VGA mode, only -vga std or -vga virtio is supported");
121914c6a894SDavid Gibson         return false;
122053018216SPaolo Bonzini     }
122153018216SPaolo Bonzini }
122253018216SPaolo Bonzini 
1223880ae7deSDavid Gibson static int spapr_post_load(void *opaque, int version_id)
1224880ae7deSDavid Gibson {
122528e02042SDavid Gibson     sPAPRMachineState *spapr = (sPAPRMachineState *)opaque;
1226880ae7deSDavid Gibson     int err = 0;
1227880ae7deSDavid Gibson 
1228631b22eaSStefan Weil     /* In earlier versions, there was no separate qdev for the PAPR
1229880ae7deSDavid Gibson      * RTC, so the RTC offset was stored directly in sPAPREnvironment.
1230880ae7deSDavid Gibson      * So when migrating from those versions, poke the incoming offset
1231880ae7deSDavid Gibson      * value into the RTC device */
1232880ae7deSDavid Gibson     if (version_id < 3) {
1233880ae7deSDavid Gibson         err = spapr_rtc_import_offset(spapr->rtc, spapr->rtc_offset);
1234880ae7deSDavid Gibson     }
1235880ae7deSDavid Gibson 
1236880ae7deSDavid Gibson     return err;
1237880ae7deSDavid Gibson }
1238880ae7deSDavid Gibson 
1239880ae7deSDavid Gibson static bool version_before_3(void *opaque, int version_id)
1240880ae7deSDavid Gibson {
1241880ae7deSDavid Gibson     return version_id < 3;
1242880ae7deSDavid Gibson }
1243880ae7deSDavid Gibson 
12444be21d56SDavid Gibson static const VMStateDescription vmstate_spapr = {
12454be21d56SDavid Gibson     .name = "spapr",
1246880ae7deSDavid Gibson     .version_id = 3,
12474be21d56SDavid Gibson     .minimum_version_id = 1,
1248880ae7deSDavid Gibson     .post_load = spapr_post_load,
12494be21d56SDavid Gibson     .fields = (VMStateField[]) {
1250880ae7deSDavid Gibson         /* used to be @next_irq */
1251880ae7deSDavid Gibson         VMSTATE_UNUSED_BUFFER(version_before_3, 0, 4),
12524be21d56SDavid Gibson 
12534be21d56SDavid Gibson         /* RTC offset */
125428e02042SDavid Gibson         VMSTATE_UINT64_TEST(rtc_offset, sPAPRMachineState, version_before_3),
1255880ae7deSDavid Gibson 
125628e02042SDavid Gibson         VMSTATE_PPC_TIMEBASE_V(tb, sPAPRMachineState, 2),
12574be21d56SDavid Gibson         VMSTATE_END_OF_LIST()
12584be21d56SDavid Gibson     },
12594be21d56SDavid Gibson };
12604be21d56SDavid Gibson 
12614be21d56SDavid Gibson static int htab_save_setup(QEMUFile *f, void *opaque)
12624be21d56SDavid Gibson {
126328e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
12644be21d56SDavid Gibson 
12654be21d56SDavid Gibson     /* "Iteration" header */
12664be21d56SDavid Gibson     qemu_put_be32(f, spapr->htab_shift);
12674be21d56SDavid Gibson 
1268e68cb8b4SAlexey Kardashevskiy     if (spapr->htab) {
1269e68cb8b4SAlexey Kardashevskiy         spapr->htab_save_index = 0;
1270e68cb8b4SAlexey Kardashevskiy         spapr->htab_first_pass = true;
1271e68cb8b4SAlexey Kardashevskiy     } else {
1272e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
12734be21d56SDavid Gibson     }
12744be21d56SDavid Gibson 
1275e68cb8b4SAlexey Kardashevskiy 
1276e68cb8b4SAlexey Kardashevskiy     return 0;
1277e68cb8b4SAlexey Kardashevskiy }
12784be21d56SDavid Gibson 
127928e02042SDavid Gibson static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr,
12804be21d56SDavid Gibson                                  int64_t max_ns)
12814be21d56SDavid Gibson {
1282378bc217SDavid Gibson     bool has_timeout = max_ns != -1;
12834be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
12844be21d56SDavid Gibson     int index = spapr->htab_save_index;
1285bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
12864be21d56SDavid Gibson 
12874be21d56SDavid Gibson     assert(spapr->htab_first_pass);
12884be21d56SDavid Gibson 
12894be21d56SDavid Gibson     do {
12904be21d56SDavid Gibson         int chunkstart;
12914be21d56SDavid Gibson 
12924be21d56SDavid Gibson         /* Consume invalid HPTEs */
12934be21d56SDavid Gibson         while ((index < htabslots)
12944be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
12954be21d56SDavid Gibson             index++;
12964be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
12974be21d56SDavid Gibson         }
12984be21d56SDavid Gibson 
12994be21d56SDavid Gibson         /* Consume valid HPTEs */
13004be21d56SDavid Gibson         chunkstart = index;
1301338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
13024be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
13034be21d56SDavid Gibson             index++;
13044be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
13054be21d56SDavid Gibson         }
13064be21d56SDavid Gibson 
13074be21d56SDavid Gibson         if (index > chunkstart) {
13084be21d56SDavid Gibson             int n_valid = index - chunkstart;
13094be21d56SDavid Gibson 
13104be21d56SDavid Gibson             qemu_put_be32(f, chunkstart);
13114be21d56SDavid Gibson             qemu_put_be16(f, n_valid);
13124be21d56SDavid Gibson             qemu_put_be16(f, 0);
13134be21d56SDavid Gibson             qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
13144be21d56SDavid Gibson                             HASH_PTE_SIZE_64 * n_valid);
13154be21d56SDavid Gibson 
1316378bc217SDavid Gibson             if (has_timeout &&
1317378bc217SDavid Gibson                 (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
13184be21d56SDavid Gibson                 break;
13194be21d56SDavid Gibson             }
13204be21d56SDavid Gibson         }
13214be21d56SDavid Gibson     } while ((index < htabslots) && !qemu_file_rate_limit(f));
13224be21d56SDavid Gibson 
13234be21d56SDavid Gibson     if (index >= htabslots) {
13244be21d56SDavid Gibson         assert(index == htabslots);
13254be21d56SDavid Gibson         index = 0;
13264be21d56SDavid Gibson         spapr->htab_first_pass = false;
13274be21d56SDavid Gibson     }
13284be21d56SDavid Gibson     spapr->htab_save_index = index;
13294be21d56SDavid Gibson }
13304be21d56SDavid Gibson 
133128e02042SDavid Gibson static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr,
13324be21d56SDavid Gibson                                 int64_t max_ns)
13334be21d56SDavid Gibson {
13344be21d56SDavid Gibson     bool final = max_ns < 0;
13354be21d56SDavid Gibson     int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
13364be21d56SDavid Gibson     int examined = 0, sent = 0;
13374be21d56SDavid Gibson     int index = spapr->htab_save_index;
1338bc72ad67SAlex Bligh     int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
13394be21d56SDavid Gibson 
13404be21d56SDavid Gibson     assert(!spapr->htab_first_pass);
13414be21d56SDavid Gibson 
13424be21d56SDavid Gibson     do {
13434be21d56SDavid Gibson         int chunkstart, invalidstart;
13444be21d56SDavid Gibson 
13454be21d56SDavid Gibson         /* Consume non-dirty HPTEs */
13464be21d56SDavid Gibson         while ((index < htabslots)
13474be21d56SDavid Gibson                && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
13484be21d56SDavid Gibson             index++;
13494be21d56SDavid Gibson             examined++;
13504be21d56SDavid Gibson         }
13514be21d56SDavid Gibson 
13524be21d56SDavid Gibson         chunkstart = index;
13534be21d56SDavid Gibson         /* Consume valid dirty HPTEs */
1354338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
13554be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
13564be21d56SDavid Gibson                && HPTE_VALID(HPTE(spapr->htab, index))) {
13574be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
13584be21d56SDavid Gibson             index++;
13594be21d56SDavid Gibson             examined++;
13604be21d56SDavid Gibson         }
13614be21d56SDavid Gibson 
13624be21d56SDavid Gibson         invalidstart = index;
13634be21d56SDavid Gibson         /* Consume invalid dirty HPTEs */
1364338c25b6SSamuel Mendoza-Jonas         while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
13654be21d56SDavid Gibson                && HPTE_DIRTY(HPTE(spapr->htab, index))
13664be21d56SDavid Gibson                && !HPTE_VALID(HPTE(spapr->htab, index))) {
13674be21d56SDavid Gibson             CLEAN_HPTE(HPTE(spapr->htab, index));
13684be21d56SDavid Gibson             index++;
13694be21d56SDavid Gibson             examined++;
13704be21d56SDavid Gibson         }
13714be21d56SDavid Gibson 
13724be21d56SDavid Gibson         if (index > chunkstart) {
13734be21d56SDavid Gibson             int n_valid = invalidstart - chunkstart;
13744be21d56SDavid Gibson             int n_invalid = index - invalidstart;
13754be21d56SDavid Gibson 
13764be21d56SDavid Gibson             qemu_put_be32(f, chunkstart);
13774be21d56SDavid Gibson             qemu_put_be16(f, n_valid);
13784be21d56SDavid Gibson             qemu_put_be16(f, n_invalid);
13794be21d56SDavid Gibson             qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
13804be21d56SDavid Gibson                             HASH_PTE_SIZE_64 * n_valid);
13814be21d56SDavid Gibson             sent += index - chunkstart;
13824be21d56SDavid Gibson 
1383bc72ad67SAlex Bligh             if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
13844be21d56SDavid Gibson                 break;
13854be21d56SDavid Gibson             }
13864be21d56SDavid Gibson         }
13874be21d56SDavid Gibson 
13884be21d56SDavid Gibson         if (examined >= htabslots) {
13894be21d56SDavid Gibson             break;
13904be21d56SDavid Gibson         }
13914be21d56SDavid Gibson 
13924be21d56SDavid Gibson         if (index >= htabslots) {
13934be21d56SDavid Gibson             assert(index == htabslots);
13944be21d56SDavid Gibson             index = 0;
13954be21d56SDavid Gibson         }
13964be21d56SDavid Gibson     } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
13974be21d56SDavid Gibson 
13984be21d56SDavid Gibson     if (index >= htabslots) {
13994be21d56SDavid Gibson         assert(index == htabslots);
14004be21d56SDavid Gibson         index = 0;
14014be21d56SDavid Gibson     }
14024be21d56SDavid Gibson 
14034be21d56SDavid Gibson     spapr->htab_save_index = index;
14044be21d56SDavid Gibson 
1405e68cb8b4SAlexey Kardashevskiy     return (examined >= htabslots) && (sent == 0) ? 1 : 0;
14064be21d56SDavid Gibson }
14074be21d56SDavid Gibson 
1408e68cb8b4SAlexey Kardashevskiy #define MAX_ITERATION_NS    5000000 /* 5 ms */
1409e68cb8b4SAlexey Kardashevskiy #define MAX_KVM_BUF_SIZE    2048
1410e68cb8b4SAlexey Kardashevskiy 
14114be21d56SDavid Gibson static int htab_save_iterate(QEMUFile *f, void *opaque)
14124be21d56SDavid Gibson {
141328e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
1414715c5407SDavid Gibson     int fd;
1415e68cb8b4SAlexey Kardashevskiy     int rc = 0;
14164be21d56SDavid Gibson 
14174be21d56SDavid Gibson     /* Iteration header */
14184be21d56SDavid Gibson     qemu_put_be32(f, 0);
14194be21d56SDavid Gibson 
1420e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
1421e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
1422e68cb8b4SAlexey Kardashevskiy 
1423715c5407SDavid Gibson         fd = get_htab_fd(spapr);
1424715c5407SDavid Gibson         if (fd < 0) {
1425715c5407SDavid Gibson             return fd;
142601a57972SSamuel Mendoza-Jonas         }
142701a57972SSamuel Mendoza-Jonas 
1428715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
1429e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
1430e68cb8b4SAlexey Kardashevskiy             return rc;
1431e68cb8b4SAlexey Kardashevskiy         }
1432e68cb8b4SAlexey Kardashevskiy     } else  if (spapr->htab_first_pass) {
14334be21d56SDavid Gibson         htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
14344be21d56SDavid Gibson     } else {
1435e68cb8b4SAlexey Kardashevskiy         rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
14364be21d56SDavid Gibson     }
14374be21d56SDavid Gibson 
14384be21d56SDavid Gibson     /* End marker */
14394be21d56SDavid Gibson     qemu_put_be32(f, 0);
14404be21d56SDavid Gibson     qemu_put_be16(f, 0);
14414be21d56SDavid Gibson     qemu_put_be16(f, 0);
14424be21d56SDavid Gibson 
1443e68cb8b4SAlexey Kardashevskiy     return rc;
14444be21d56SDavid Gibson }
14454be21d56SDavid Gibson 
14464be21d56SDavid Gibson static int htab_save_complete(QEMUFile *f, void *opaque)
14474be21d56SDavid Gibson {
144828e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
1449715c5407SDavid Gibson     int fd;
14504be21d56SDavid Gibson 
14514be21d56SDavid Gibson     /* Iteration header */
14524be21d56SDavid Gibson     qemu_put_be32(f, 0);
14534be21d56SDavid Gibson 
1454e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
1455e68cb8b4SAlexey Kardashevskiy         int rc;
1456e68cb8b4SAlexey Kardashevskiy 
1457e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
1458e68cb8b4SAlexey Kardashevskiy 
1459715c5407SDavid Gibson         fd = get_htab_fd(spapr);
1460715c5407SDavid Gibson         if (fd < 0) {
1461715c5407SDavid Gibson             return fd;
146201a57972SSamuel Mendoza-Jonas         }
146301a57972SSamuel Mendoza-Jonas 
1464715c5407SDavid Gibson         rc = kvmppc_save_htab(f, fd, MAX_KVM_BUF_SIZE, -1);
1465e68cb8b4SAlexey Kardashevskiy         if (rc < 0) {
1466e68cb8b4SAlexey Kardashevskiy             return rc;
1467e68cb8b4SAlexey Kardashevskiy         }
1468e68cb8b4SAlexey Kardashevskiy     } else {
1469378bc217SDavid Gibson         if (spapr->htab_first_pass) {
1470378bc217SDavid Gibson             htab_save_first_pass(f, spapr, -1);
1471378bc217SDavid Gibson         }
14724be21d56SDavid Gibson         htab_save_later_pass(f, spapr, -1);
1473e68cb8b4SAlexey Kardashevskiy     }
14744be21d56SDavid Gibson 
14754be21d56SDavid Gibson     /* End marker */
14764be21d56SDavid Gibson     qemu_put_be32(f, 0);
14774be21d56SDavid Gibson     qemu_put_be16(f, 0);
14784be21d56SDavid Gibson     qemu_put_be16(f, 0);
14794be21d56SDavid Gibson 
14804be21d56SDavid Gibson     return 0;
14814be21d56SDavid Gibson }
14824be21d56SDavid Gibson 
14834be21d56SDavid Gibson static int htab_load(QEMUFile *f, void *opaque, int version_id)
14844be21d56SDavid Gibson {
148528e02042SDavid Gibson     sPAPRMachineState *spapr = opaque;
14864be21d56SDavid Gibson     uint32_t section_hdr;
1487e68cb8b4SAlexey Kardashevskiy     int fd = -1;
14884be21d56SDavid Gibson 
14894be21d56SDavid Gibson     if (version_id < 1 || version_id > 1) {
149098a5d100SDavid Gibson         error_report("htab_load() bad version");
14914be21d56SDavid Gibson         return -EINVAL;
14924be21d56SDavid Gibson     }
14934be21d56SDavid Gibson 
14944be21d56SDavid Gibson     section_hdr = qemu_get_be32(f);
14954be21d56SDavid Gibson 
14964be21d56SDavid Gibson     if (section_hdr) {
14979897e462SGreg Kurz         Error *local_err = NULL;
1498c5f54f3eSDavid Gibson 
1499c5f54f3eSDavid Gibson         /* First section gives the htab size */
1500c5f54f3eSDavid Gibson         spapr_reallocate_hpt(spapr, section_hdr, &local_err);
1501c5f54f3eSDavid Gibson         if (local_err) {
1502c5f54f3eSDavid Gibson             error_report_err(local_err);
15034be21d56SDavid Gibson             return -EINVAL;
15044be21d56SDavid Gibson         }
15054be21d56SDavid Gibson         return 0;
15064be21d56SDavid Gibson     }
15074be21d56SDavid Gibson 
1508e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
1509e68cb8b4SAlexey Kardashevskiy         assert(kvm_enabled());
1510e68cb8b4SAlexey Kardashevskiy 
1511e68cb8b4SAlexey Kardashevskiy         fd = kvmppc_get_htab_fd(true);
1512e68cb8b4SAlexey Kardashevskiy         if (fd < 0) {
151398a5d100SDavid Gibson             error_report("Unable to open fd to restore KVM hash table: %s",
1514e68cb8b4SAlexey Kardashevskiy                          strerror(errno));
1515e68cb8b4SAlexey Kardashevskiy         }
1516e68cb8b4SAlexey Kardashevskiy     }
1517e68cb8b4SAlexey Kardashevskiy 
15184be21d56SDavid Gibson     while (true) {
15194be21d56SDavid Gibson         uint32_t index;
15204be21d56SDavid Gibson         uint16_t n_valid, n_invalid;
15214be21d56SDavid Gibson 
15224be21d56SDavid Gibson         index = qemu_get_be32(f);
15234be21d56SDavid Gibson         n_valid = qemu_get_be16(f);
15244be21d56SDavid Gibson         n_invalid = qemu_get_be16(f);
15254be21d56SDavid Gibson 
15264be21d56SDavid Gibson         if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
15274be21d56SDavid Gibson             /* End of Stream */
15284be21d56SDavid Gibson             break;
15294be21d56SDavid Gibson         }
15304be21d56SDavid Gibson 
1531e68cb8b4SAlexey Kardashevskiy         if ((index + n_valid + n_invalid) >
15324be21d56SDavid Gibson             (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
15334be21d56SDavid Gibson             /* Bad index in stream */
153498a5d100SDavid Gibson             error_report(
153598a5d100SDavid Gibson                 "htab_load() bad index %d (%hd+%hd entries) in htab stream (htab_shift=%d)",
153698a5d100SDavid Gibson                 index, n_valid, n_invalid, spapr->htab_shift);
15374be21d56SDavid Gibson             return -EINVAL;
15384be21d56SDavid Gibson         }
15394be21d56SDavid Gibson 
1540e68cb8b4SAlexey Kardashevskiy         if (spapr->htab) {
15414be21d56SDavid Gibson             if (n_valid) {
15424be21d56SDavid Gibson                 qemu_get_buffer(f, HPTE(spapr->htab, index),
15434be21d56SDavid Gibson                                 HASH_PTE_SIZE_64 * n_valid);
15444be21d56SDavid Gibson             }
15454be21d56SDavid Gibson             if (n_invalid) {
15464be21d56SDavid Gibson                 memset(HPTE(spapr->htab, index + n_valid), 0,
15474be21d56SDavid Gibson                        HASH_PTE_SIZE_64 * n_invalid);
15484be21d56SDavid Gibson             }
1549e68cb8b4SAlexey Kardashevskiy         } else {
1550e68cb8b4SAlexey Kardashevskiy             int rc;
1551e68cb8b4SAlexey Kardashevskiy 
1552e68cb8b4SAlexey Kardashevskiy             assert(fd >= 0);
1553e68cb8b4SAlexey Kardashevskiy 
1554e68cb8b4SAlexey Kardashevskiy             rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid);
1555e68cb8b4SAlexey Kardashevskiy             if (rc < 0) {
1556e68cb8b4SAlexey Kardashevskiy                 return rc;
1557e68cb8b4SAlexey Kardashevskiy             }
1558e68cb8b4SAlexey Kardashevskiy         }
1559e68cb8b4SAlexey Kardashevskiy     }
1560e68cb8b4SAlexey Kardashevskiy 
1561e68cb8b4SAlexey Kardashevskiy     if (!spapr->htab) {
1562e68cb8b4SAlexey Kardashevskiy         assert(fd >= 0);
1563e68cb8b4SAlexey Kardashevskiy         close(fd);
15644be21d56SDavid Gibson     }
15654be21d56SDavid Gibson 
15664be21d56SDavid Gibson     return 0;
15674be21d56SDavid Gibson }
15684be21d56SDavid Gibson 
1569c573fc03SThomas Huth static void htab_cleanup(void *opaque)
1570c573fc03SThomas Huth {
1571c573fc03SThomas Huth     sPAPRMachineState *spapr = opaque;
1572c573fc03SThomas Huth 
1573c573fc03SThomas Huth     close_htab_fd(spapr);
1574c573fc03SThomas Huth }
1575c573fc03SThomas Huth 
15764be21d56SDavid Gibson static SaveVMHandlers savevm_htab_handlers = {
15774be21d56SDavid Gibson     .save_live_setup = htab_save_setup,
15784be21d56SDavid Gibson     .save_live_iterate = htab_save_iterate,
1579a3e06c3dSDr. David Alan Gilbert     .save_live_complete_precopy = htab_save_complete,
1580c573fc03SThomas Huth     .cleanup = htab_cleanup,
15814be21d56SDavid Gibson     .load_state = htab_load,
15824be21d56SDavid Gibson };
15834be21d56SDavid Gibson 
15845b2128d2SAlexander Graf static void spapr_boot_set(void *opaque, const char *boot_device,
15855b2128d2SAlexander Graf                            Error **errp)
15865b2128d2SAlexander Graf {
15875b2128d2SAlexander Graf     MachineState *machine = MACHINE(qdev_get_machine());
15885b2128d2SAlexander Graf     machine->boot_order = g_strdup(boot_device);
15895b2128d2SAlexander Graf }
15905b2128d2SAlexander Graf 
1591224245bfSDavid Gibson /*
1592224245bfSDavid Gibson  * Reset routine for LMB DR devices.
1593224245bfSDavid Gibson  *
1594224245bfSDavid Gibson  * Unlike PCI DR devices, LMB DR devices explicitly register this reset
1595224245bfSDavid Gibson  * routine. Reset for PCI DR devices will be handled by PHB reset routine
1596224245bfSDavid Gibson  * when it walks all its children devices. LMB devices reset occurs
1597224245bfSDavid Gibson  * as part of spapr_ppc_reset().
1598224245bfSDavid Gibson  */
1599224245bfSDavid Gibson static void spapr_drc_reset(void *opaque)
1600224245bfSDavid Gibson {
1601224245bfSDavid Gibson     sPAPRDRConnector *drc = opaque;
1602224245bfSDavid Gibson     DeviceState *d = DEVICE(drc);
1603224245bfSDavid Gibson 
1604224245bfSDavid Gibson     if (d) {
1605224245bfSDavid Gibson         device_reset(d);
1606224245bfSDavid Gibson     }
1607224245bfSDavid Gibson }
1608224245bfSDavid Gibson 
1609224245bfSDavid Gibson static void spapr_create_lmb_dr_connectors(sPAPRMachineState *spapr)
1610224245bfSDavid Gibson {
1611224245bfSDavid Gibson     MachineState *machine = MACHINE(spapr);
1612224245bfSDavid Gibson     uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
1613e8f986fcSBharata B Rao     uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
1614224245bfSDavid Gibson     int i;
1615224245bfSDavid Gibson 
1616224245bfSDavid Gibson     for (i = 0; i < nr_lmbs; i++) {
1617224245bfSDavid Gibson         sPAPRDRConnector *drc;
1618224245bfSDavid Gibson         uint64_t addr;
1619224245bfSDavid Gibson 
1620e8f986fcSBharata B Rao         addr = i * lmb_size + spapr->hotplug_memory.base;
1621224245bfSDavid Gibson         drc = spapr_dr_connector_new(OBJECT(spapr), SPAPR_DR_CONNECTOR_TYPE_LMB,
1622224245bfSDavid Gibson                                      addr/lmb_size);
1623224245bfSDavid Gibson         qemu_register_reset(spapr_drc_reset, drc);
1624224245bfSDavid Gibson     }
1625224245bfSDavid Gibson }
1626224245bfSDavid Gibson 
1627224245bfSDavid Gibson /*
1628224245bfSDavid Gibson  * If RAM size, maxmem size and individual node mem sizes aren't aligned
1629224245bfSDavid Gibson  * to SPAPR_MEMORY_BLOCK_SIZE(256MB), then refuse to start the guest
1630224245bfSDavid Gibson  * since we can't support such unaligned sizes with DRCONF_MEMORY.
1631224245bfSDavid Gibson  */
16327c150d6fSDavid Gibson static void spapr_validate_node_memory(MachineState *machine, Error **errp)
1633224245bfSDavid Gibson {
1634224245bfSDavid Gibson     int i;
1635224245bfSDavid Gibson 
16367c150d6fSDavid Gibson     if (machine->ram_size % SPAPR_MEMORY_BLOCK_SIZE) {
16377c150d6fSDavid Gibson         error_setg(errp, "Memory size 0x" RAM_ADDR_FMT
16387c150d6fSDavid Gibson                    " is not aligned to %llu MiB",
16397c150d6fSDavid Gibson                    machine->ram_size,
1640224245bfSDavid Gibson                    SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
16417c150d6fSDavid Gibson         return;
16427c150d6fSDavid Gibson     }
16437c150d6fSDavid Gibson 
16447c150d6fSDavid Gibson     if (machine->maxram_size % SPAPR_MEMORY_BLOCK_SIZE) {
16457c150d6fSDavid Gibson         error_setg(errp, "Maximum memory size 0x" RAM_ADDR_FMT
16467c150d6fSDavid Gibson                    " is not aligned to %llu MiB",
16477c150d6fSDavid Gibson                    machine->ram_size,
16487c150d6fSDavid Gibson                    SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
16497c150d6fSDavid Gibson         return;
1650224245bfSDavid Gibson     }
1651224245bfSDavid Gibson 
1652224245bfSDavid Gibson     for (i = 0; i < nb_numa_nodes; i++) {
1653224245bfSDavid Gibson         if (numa_info[i].node_mem % SPAPR_MEMORY_BLOCK_SIZE) {
16547c150d6fSDavid Gibson             error_setg(errp,
16557c150d6fSDavid Gibson                        "Node %d memory size 0x%" PRIx64
16567c150d6fSDavid Gibson                        " is not aligned to %llu MiB",
16577c150d6fSDavid Gibson                        i, numa_info[i].node_mem,
1658224245bfSDavid Gibson                        SPAPR_MEMORY_BLOCK_SIZE / M_BYTE);
16597c150d6fSDavid Gibson             return;
1660224245bfSDavid Gibson         }
1661224245bfSDavid Gibson     }
1662224245bfSDavid Gibson }
1663224245bfSDavid Gibson 
166453018216SPaolo Bonzini /* pSeries LPAR / sPAPR hardware init */
16653ef96221SMarcel Apfelbaum static void ppc_spapr_init(MachineState *machine)
166653018216SPaolo Bonzini {
166728e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
16683c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(machine);
1669224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
16703ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
16713ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
16723ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
167353018216SPaolo Bonzini     PCIHostState *phb;
167453018216SPaolo Bonzini     int i;
167553018216SPaolo Bonzini     MemoryRegion *sysmem = get_system_memory();
167653018216SPaolo Bonzini     MemoryRegion *ram = g_new(MemoryRegion, 1);
1677658fa66bSAlexey Kardashevskiy     MemoryRegion *rma_region;
1678658fa66bSAlexey Kardashevskiy     void *rma = NULL;
167953018216SPaolo Bonzini     hwaddr rma_alloc_size;
1680b082d65aSAlexey Kardashevskiy     hwaddr node0_size = spapr_node0_size();
168153018216SPaolo Bonzini     uint32_t initrd_base = 0;
168253018216SPaolo Bonzini     long kernel_size = 0, initrd_size = 0;
1683b7d1f77aSBenjamin Herrenschmidt     long load_limit, fw_size;
168416457e7fSBenjamin Herrenschmidt     bool kernel_le = false;
168553018216SPaolo Bonzini     char *filename;
168694a94e4cSBharata B Rao     int smt = kvmppc_smt_threads();
168794a94e4cSBharata B Rao     int spapr_cores = smp_cpus / smp_threads;
168894a94e4cSBharata B Rao     int spapr_max_cores = max_cpus / smp_threads;
168994a94e4cSBharata B Rao 
16903c0c47e3SDavid Gibson     if (mc->query_hotpluggable_cpus) {
169194a94e4cSBharata B Rao         if (smp_cpus % smp_threads) {
169294a94e4cSBharata B Rao             error_report("smp_cpus (%u) must be multiple of threads (%u)",
169394a94e4cSBharata B Rao                          smp_cpus, smp_threads);
169494a94e4cSBharata B Rao             exit(1);
169594a94e4cSBharata B Rao         }
169694a94e4cSBharata B Rao         if (max_cpus % smp_threads) {
169794a94e4cSBharata B Rao             error_report("max_cpus (%u) must be multiple of threads (%u)",
169894a94e4cSBharata B Rao                          max_cpus, smp_threads);
169994a94e4cSBharata B Rao             exit(1);
170094a94e4cSBharata B Rao         }
170194a94e4cSBharata B Rao     }
170253018216SPaolo Bonzini 
1703226419d6SMichael S. Tsirkin     msi_nonbroken = true;
170453018216SPaolo Bonzini 
170553018216SPaolo Bonzini     QLIST_INIT(&spapr->phbs);
170653018216SPaolo Bonzini 
170753018216SPaolo Bonzini     cpu_ppc_hypercall = emulate_spapr_hypercall;
170853018216SPaolo Bonzini 
170953018216SPaolo Bonzini     /* Allocate RMA if necessary */
1710658fa66bSAlexey Kardashevskiy     rma_alloc_size = kvmppc_alloc_rma(&rma);
171153018216SPaolo Bonzini 
171253018216SPaolo Bonzini     if (rma_alloc_size == -1) {
1713730fce59SThomas Huth         error_report("Unable to create RMA");
171453018216SPaolo Bonzini         exit(1);
171553018216SPaolo Bonzini     }
171653018216SPaolo Bonzini 
1717c4177479SAlexey Kardashevskiy     if (rma_alloc_size && (rma_alloc_size < node0_size)) {
171853018216SPaolo Bonzini         spapr->rma_size = rma_alloc_size;
171953018216SPaolo Bonzini     } else {
1720c4177479SAlexey Kardashevskiy         spapr->rma_size = node0_size;
172153018216SPaolo Bonzini 
172253018216SPaolo Bonzini         /* With KVM, we don't actually know whether KVM supports an
172353018216SPaolo Bonzini          * unbounded RMA (PR KVM) or is limited by the hash table size
172453018216SPaolo Bonzini          * (HV KVM using VRMA), so we always assume the latter
172553018216SPaolo Bonzini          *
172653018216SPaolo Bonzini          * In that case, we also limit the initial allocations for RTAS
172753018216SPaolo Bonzini          * etc... to 256M since we have no way to know what the VRMA size
172853018216SPaolo Bonzini          * is going to be as it depends on the size of the hash table
172953018216SPaolo Bonzini          * isn't determined yet.
173053018216SPaolo Bonzini          */
173153018216SPaolo Bonzini         if (kvm_enabled()) {
173253018216SPaolo Bonzini             spapr->vrma_adjust = 1;
173353018216SPaolo Bonzini             spapr->rma_size = MIN(spapr->rma_size, 0x10000000);
173453018216SPaolo Bonzini         }
1735912acdf4SBenjamin Herrenschmidt 
1736912acdf4SBenjamin Herrenschmidt         /* Actually we don't support unbounded RMA anymore since we
1737912acdf4SBenjamin Herrenschmidt          * added proper emulation of HV mode. The max we can get is
1738912acdf4SBenjamin Herrenschmidt          * 16G which also happens to be what we configure for PAPR
1739912acdf4SBenjamin Herrenschmidt          * mode so make sure we don't do anything bigger than that
1740912acdf4SBenjamin Herrenschmidt          */
1741912acdf4SBenjamin Herrenschmidt         spapr->rma_size = MIN(spapr->rma_size, 0x400000000ull);
174253018216SPaolo Bonzini     }
174353018216SPaolo Bonzini 
1744c4177479SAlexey Kardashevskiy     if (spapr->rma_size > node0_size) {
1745d54e4d76SDavid Gibson         error_report("Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")",
1746c4177479SAlexey Kardashevskiy                      spapr->rma_size);
1747c4177479SAlexey Kardashevskiy         exit(1);
1748c4177479SAlexey Kardashevskiy     }
1749c4177479SAlexey Kardashevskiy 
1750b7d1f77aSBenjamin Herrenschmidt     /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
1751b7d1f77aSBenjamin Herrenschmidt     load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
175253018216SPaolo Bonzini 
17537b565160SDavid Gibson     /* Set up Interrupt Controller before we create the VCPUs */
175427f24582SBenjamin Herrenschmidt     spapr->xics = xics_system_init(machine,
175594a94e4cSBharata B Rao                                    DIV_ROUND_UP(max_cpus * smt, smp_threads),
1756161deaf2SBenjamin Herrenschmidt                                    XICS_IRQS_SPAPR, &error_fatal);
17577b565160SDavid Gibson 
1758224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
17597c150d6fSDavid Gibson         spapr_validate_node_memory(machine, &error_fatal);
1760224245bfSDavid Gibson     }
1761224245bfSDavid Gibson 
176253018216SPaolo Bonzini     /* init CPUs */
176319fb2c36SBharata B Rao     if (machine->cpu_model == NULL) {
176419fb2c36SBharata B Rao         machine->cpu_model = kvm_enabled() ? "host" : "POWER7";
176553018216SPaolo Bonzini     }
176694a94e4cSBharata B Rao 
1767e703d2f7SGreg Kurz     ppc_cpu_parse_features(machine->cpu_model);
1768e703d2f7SGreg Kurz 
17693c0c47e3SDavid Gibson     if (mc->query_hotpluggable_cpus) {
177094a94e4cSBharata B Rao         char *type = spapr_get_cpu_core_type(machine->cpu_model);
177194a94e4cSBharata B Rao 
17724babfaf0SThomas Huth         if (type == NULL) {
1773caebf378SCédric Le Goater             error_report("Unable to find sPAPR CPU Core definition");
1774caebf378SCédric Le Goater             exit(1);
1775caebf378SCédric Le Goater         }
1776caebf378SCédric Le Goater 
177794a94e4cSBharata B Rao         spapr->cores = g_new0(Object *, spapr_max_cores);
1778af81cf32SBharata B Rao         for (i = 0; i < spapr_max_cores; i++) {
177912bf2d33SGreg Kurz             int core_id = i * smp_threads;
1780af81cf32SBharata B Rao             sPAPRDRConnector *drc =
1781af81cf32SBharata B Rao                 spapr_dr_connector_new(OBJECT(spapr),
178212bf2d33SGreg Kurz                                        SPAPR_DR_CONNECTOR_TYPE_CPU,
178312bf2d33SGreg Kurz                                        (core_id / smp_threads) * smt);
1784af81cf32SBharata B Rao 
1785af81cf32SBharata B Rao             qemu_register_reset(spapr_drc_reset, drc);
1786af81cf32SBharata B Rao 
1787af81cf32SBharata B Rao             if (i < spapr_cores) {
1788caebf378SCédric Le Goater                 Object *core  = object_new(type);
178994a94e4cSBharata B Rao                 object_property_set_int(core, smp_threads, "nr-threads",
179094a94e4cSBharata B Rao                                         &error_fatal);
179112bf2d33SGreg Kurz                 object_property_set_int(core, core_id, CPU_CORE_PROP_CORE_ID,
179294a94e4cSBharata B Rao                                         &error_fatal);
179394a94e4cSBharata B Rao                 object_property_set_bool(core, true, "realized", &error_fatal);
179494a94e4cSBharata B Rao             }
1795af81cf32SBharata B Rao         }
179694a94e4cSBharata B Rao         g_free(type);
179794a94e4cSBharata B Rao     } else {
179853018216SPaolo Bonzini         for (i = 0; i < smp_cpus; i++) {
179994a94e4cSBharata B Rao             PowerPCCPU *cpu = cpu_ppc_init(machine->cpu_model);
180053018216SPaolo Bonzini             if (cpu == NULL) {
1801569f4967SDavid Gibson                 error_report("Unable to find PowerPC CPU definition");
180253018216SPaolo Bonzini                 exit(1);
180353018216SPaolo Bonzini             }
1804569f4967SDavid Gibson             spapr_cpu_init(spapr, cpu, &error_fatal);
180553018216SPaolo Bonzini        }
180694a94e4cSBharata B Rao     }
180753018216SPaolo Bonzini 
1808026bfd89SDavid Gibson     if (kvm_enabled()) {
1809026bfd89SDavid Gibson         /* Enable H_LOGICAL_CI_* so SLOF can talk to in-kernel devices */
1810026bfd89SDavid Gibson         kvmppc_enable_logical_ci_hcalls();
1811ef9971ddSAlexey Kardashevskiy         kvmppc_enable_set_mode_hcall();
18125145ad4fSNathan Whitehorn 
18135145ad4fSNathan Whitehorn         /* H_CLEAR_MOD/_REF are mandatory in PAPR, but off by default */
18145145ad4fSNathan Whitehorn         kvmppc_enable_clear_ref_mod_hcalls();
1815026bfd89SDavid Gibson     }
1816026bfd89SDavid Gibson 
181753018216SPaolo Bonzini     /* allocate RAM */
1818f92f5da1SAlexey Kardashevskiy     memory_region_allocate_system_memory(ram, NULL, "ppc_spapr.ram",
1819fb164994SDavid Gibson                                          machine->ram_size);
1820f92f5da1SAlexey Kardashevskiy     memory_region_add_subregion(sysmem, 0, ram);
182153018216SPaolo Bonzini 
1822658fa66bSAlexey Kardashevskiy     if (rma_alloc_size && rma) {
1823658fa66bSAlexey Kardashevskiy         rma_region = g_new(MemoryRegion, 1);
1824658fa66bSAlexey Kardashevskiy         memory_region_init_ram_ptr(rma_region, NULL, "ppc_spapr.rma",
1825658fa66bSAlexey Kardashevskiy                                    rma_alloc_size, rma);
1826658fa66bSAlexey Kardashevskiy         vmstate_register_ram_global(rma_region);
1827658fa66bSAlexey Kardashevskiy         memory_region_add_subregion(sysmem, 0, rma_region);
1828658fa66bSAlexey Kardashevskiy     }
1829658fa66bSAlexey Kardashevskiy 
18304a1c9cf0SBharata B Rao     /* initialize hotplug memory address space */
18314a1c9cf0SBharata B Rao     if (machine->ram_size < machine->maxram_size) {
18324a1c9cf0SBharata B Rao         ram_addr_t hotplug_mem_size = machine->maxram_size - machine->ram_size;
183371c9a3ddSBharata B Rao         /*
183471c9a3ddSBharata B Rao          * Limit the number of hotpluggable memory slots to half the number
183571c9a3ddSBharata B Rao          * slots that KVM supports, leaving the other half for PCI and other
183671c9a3ddSBharata B Rao          * devices. However ensure that number of slots doesn't drop below 32.
183771c9a3ddSBharata B Rao          */
183871c9a3ddSBharata B Rao         int max_memslots = kvm_enabled() ? kvm_get_max_memslots() / 2 :
183971c9a3ddSBharata B Rao                            SPAPR_MAX_RAM_SLOTS;
18404a1c9cf0SBharata B Rao 
184171c9a3ddSBharata B Rao         if (max_memslots < SPAPR_MAX_RAM_SLOTS) {
184271c9a3ddSBharata B Rao             max_memslots = SPAPR_MAX_RAM_SLOTS;
184371c9a3ddSBharata B Rao         }
184471c9a3ddSBharata B Rao         if (machine->ram_slots > max_memslots) {
1845d54e4d76SDavid Gibson             error_report("Specified number of memory slots %"
1846d54e4d76SDavid Gibson                          PRIu64" exceeds max supported %d",
184771c9a3ddSBharata B Rao                          machine->ram_slots, max_memslots);
1848d54e4d76SDavid Gibson             exit(1);
18494a1c9cf0SBharata B Rao         }
18504a1c9cf0SBharata B Rao 
18514a1c9cf0SBharata B Rao         spapr->hotplug_memory.base = ROUND_UP(machine->ram_size,
18524a1c9cf0SBharata B Rao                                               SPAPR_HOTPLUG_MEM_ALIGN);
18534a1c9cf0SBharata B Rao         memory_region_init(&spapr->hotplug_memory.mr, OBJECT(spapr),
18544a1c9cf0SBharata B Rao                            "hotplug-memory", hotplug_mem_size);
18554a1c9cf0SBharata B Rao         memory_region_add_subregion(sysmem, spapr->hotplug_memory.base,
18564a1c9cf0SBharata B Rao                                     &spapr->hotplug_memory.mr);
18574a1c9cf0SBharata B Rao     }
18584a1c9cf0SBharata B Rao 
1859224245bfSDavid Gibson     if (smc->dr_lmb_enabled) {
1860224245bfSDavid Gibson         spapr_create_lmb_dr_connectors(spapr);
1861224245bfSDavid Gibson     }
1862224245bfSDavid Gibson 
186353018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
18644c56440dSStefan Weil     if (!filename) {
1865730fce59SThomas Huth         error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
18664c56440dSStefan Weil         exit(1);
18674c56440dSStefan Weil     }
1868b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_size = get_image_size(filename);
18698afc22a2SZhou Jie     if (spapr->rtas_size < 0) {
18708afc22a2SZhou Jie         error_report("Could not get size of LPAR rtas '%s'", filename);
18718afc22a2SZhou Jie         exit(1);
18728afc22a2SZhou Jie     }
1873b7d1f77aSBenjamin Herrenschmidt     spapr->rtas_blob = g_malloc(spapr->rtas_size);
1874b7d1f77aSBenjamin Herrenschmidt     if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
1875730fce59SThomas Huth         error_report("Could not load LPAR rtas '%s'", filename);
187653018216SPaolo Bonzini         exit(1);
187753018216SPaolo Bonzini     }
187853018216SPaolo Bonzini     if (spapr->rtas_size > RTAS_MAX_SIZE) {
1879730fce59SThomas Huth         error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
18802f285bddSPeter Maydell                      (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
188153018216SPaolo Bonzini         exit(1);
188253018216SPaolo Bonzini     }
188353018216SPaolo Bonzini     g_free(filename);
188453018216SPaolo Bonzini 
188553018216SPaolo Bonzini     /* Set up EPOW events infrastructure */
188653018216SPaolo Bonzini     spapr_events_init(spapr);
188753018216SPaolo Bonzini 
188812f42174SDavid Gibson     /* Set up the RTC RTAS interfaces */
188928df36a1SDavid Gibson     spapr_rtc_create(spapr);
189012f42174SDavid Gibson 
189153018216SPaolo Bonzini     /* Set up VIO bus */
189253018216SPaolo Bonzini     spapr->vio_bus = spapr_vio_bus_init();
189353018216SPaolo Bonzini 
189453018216SPaolo Bonzini     for (i = 0; i < MAX_SERIAL_PORTS; i++) {
189553018216SPaolo Bonzini         if (serial_hds[i]) {
189653018216SPaolo Bonzini             spapr_vty_create(spapr->vio_bus, serial_hds[i]);
189753018216SPaolo Bonzini         }
189853018216SPaolo Bonzini     }
189953018216SPaolo Bonzini 
190053018216SPaolo Bonzini     /* We always have at least the nvram device on VIO */
190153018216SPaolo Bonzini     spapr_create_nvram(spapr);
190253018216SPaolo Bonzini 
190353018216SPaolo Bonzini     /* Set up PCI */
190453018216SPaolo Bonzini     spapr_pci_rtas_init();
190553018216SPaolo Bonzini 
190689dfd6e1SDavid Gibson     phb = spapr_create_phb(spapr, 0);
190753018216SPaolo Bonzini 
190853018216SPaolo Bonzini     for (i = 0; i < nb_nics; i++) {
190953018216SPaolo Bonzini         NICInfo *nd = &nd_table[i];
191053018216SPaolo Bonzini 
191153018216SPaolo Bonzini         if (!nd->model) {
191253018216SPaolo Bonzini             nd->model = g_strdup("ibmveth");
191353018216SPaolo Bonzini         }
191453018216SPaolo Bonzini 
191553018216SPaolo Bonzini         if (strcmp(nd->model, "ibmveth") == 0) {
191653018216SPaolo Bonzini             spapr_vlan_create(spapr->vio_bus, nd);
191753018216SPaolo Bonzini         } else {
191829b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], phb->bus, nd->model, NULL);
191953018216SPaolo Bonzini         }
192053018216SPaolo Bonzini     }
192153018216SPaolo Bonzini 
192253018216SPaolo Bonzini     for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
192353018216SPaolo Bonzini         spapr_vscsi_create(spapr->vio_bus);
192453018216SPaolo Bonzini     }
192553018216SPaolo Bonzini 
192653018216SPaolo Bonzini     /* Graphics */
192714c6a894SDavid Gibson     if (spapr_vga_init(phb->bus, &error_fatal)) {
192853018216SPaolo Bonzini         spapr->has_graphics = true;
1929c6e76503SPaolo Bonzini         machine->usb |= defaults_enabled() && !machine->usb_disabled;
193053018216SPaolo Bonzini     }
193153018216SPaolo Bonzini 
19324ee9ced9SMarcel Apfelbaum     if (machine->usb) {
193357040d45SThomas Huth         if (smc->use_ohci_by_default) {
193453018216SPaolo Bonzini             pci_create_simple(phb->bus, -1, "pci-ohci");
193557040d45SThomas Huth         } else {
193657040d45SThomas Huth             pci_create_simple(phb->bus, -1, "nec-usb-xhci");
193757040d45SThomas Huth         }
1938c86580b8SMarkus Armbruster 
193953018216SPaolo Bonzini         if (spapr->has_graphics) {
1940c86580b8SMarkus Armbruster             USBBus *usb_bus = usb_bus_find(-1);
1941c86580b8SMarkus Armbruster 
1942c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-kbd");
1943c86580b8SMarkus Armbruster             usb_create_simple(usb_bus, "usb-mouse");
194453018216SPaolo Bonzini         }
194553018216SPaolo Bonzini     }
194653018216SPaolo Bonzini 
194753018216SPaolo Bonzini     if (spapr->rma_size < (MIN_RMA_SLOF << 20)) {
1948d54e4d76SDavid Gibson         error_report(
1949d54e4d76SDavid Gibson             "pSeries SLOF firmware requires >= %ldM guest RMA (Real Mode Area memory)",
1950d54e4d76SDavid Gibson             MIN_RMA_SLOF);
195153018216SPaolo Bonzini         exit(1);
195253018216SPaolo Bonzini     }
195353018216SPaolo Bonzini 
195453018216SPaolo Bonzini     if (kernel_filename) {
195553018216SPaolo Bonzini         uint64_t lowaddr = 0;
195653018216SPaolo Bonzini 
195753018216SPaolo Bonzini         kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
19587ef295eaSPeter Crosthwaite                                NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
19597ef295eaSPeter Crosthwaite                                0, 0);
19603b66da82SAlexey Kardashevskiy         if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
196116457e7fSBenjamin Herrenschmidt             kernel_size = load_elf(kernel_filename,
196216457e7fSBenjamin Herrenschmidt                                    translate_kernel_address, NULL,
19637ef295eaSPeter Crosthwaite                                    NULL, &lowaddr, NULL, 0, PPC_ELF_MACHINE,
19647ef295eaSPeter Crosthwaite                                    0, 0);
196516457e7fSBenjamin Herrenschmidt             kernel_le = kernel_size > 0;
196616457e7fSBenjamin Herrenschmidt         }
196716457e7fSBenjamin Herrenschmidt         if (kernel_size < 0) {
1968d54e4d76SDavid Gibson             error_report("error loading %s: %s",
19693b66da82SAlexey Kardashevskiy                          kernel_filename, load_elf_strerror(kernel_size));
197053018216SPaolo Bonzini             exit(1);
197153018216SPaolo Bonzini         }
197253018216SPaolo Bonzini 
197353018216SPaolo Bonzini         /* load initrd */
197453018216SPaolo Bonzini         if (initrd_filename) {
197553018216SPaolo Bonzini             /* Try to locate the initrd in the gap between the kernel
197653018216SPaolo Bonzini              * and the firmware. Add a bit of space just in case
197753018216SPaolo Bonzini              */
197853018216SPaolo Bonzini             initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
197953018216SPaolo Bonzini             initrd_size = load_image_targphys(initrd_filename, initrd_base,
198053018216SPaolo Bonzini                                               load_limit - initrd_base);
198153018216SPaolo Bonzini             if (initrd_size < 0) {
1982d54e4d76SDavid Gibson                 error_report("could not load initial ram disk '%s'",
198353018216SPaolo Bonzini                              initrd_filename);
198453018216SPaolo Bonzini                 exit(1);
198553018216SPaolo Bonzini             }
198653018216SPaolo Bonzini         } else {
198753018216SPaolo Bonzini             initrd_base = 0;
198853018216SPaolo Bonzini             initrd_size = 0;
198953018216SPaolo Bonzini         }
199053018216SPaolo Bonzini     }
199153018216SPaolo Bonzini 
19928e7ea787SAndreas Färber     if (bios_name == NULL) {
19938e7ea787SAndreas Färber         bios_name = FW_FILE_NAME;
19948e7ea787SAndreas Färber     }
19958e7ea787SAndreas Färber     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
19964c56440dSStefan Weil     if (!filename) {
199768fea5a0SThomas Huth         error_report("Could not find LPAR firmware '%s'", bios_name);
19984c56440dSStefan Weil         exit(1);
19994c56440dSStefan Weil     }
200053018216SPaolo Bonzini     fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
200168fea5a0SThomas Huth     if (fw_size <= 0) {
200268fea5a0SThomas Huth         error_report("Could not load LPAR firmware '%s'", filename);
200353018216SPaolo Bonzini         exit(1);
200453018216SPaolo Bonzini     }
200553018216SPaolo Bonzini     g_free(filename);
200653018216SPaolo Bonzini 
200728e02042SDavid Gibson     /* FIXME: Should register things through the MachineState's qdev
200828e02042SDavid Gibson      * interface, this is a legacy from the sPAPREnvironment structure
200928e02042SDavid Gibson      * which predated MachineState but had a similar function */
20104be21d56SDavid Gibson     vmstate_register(NULL, 0, &vmstate_spapr, spapr);
20114be21d56SDavid Gibson     register_savevm_live(NULL, "spapr/htab", -1, 1,
20124be21d56SDavid Gibson                          &savevm_htab_handlers, spapr);
20134be21d56SDavid Gibson 
201453018216SPaolo Bonzini     /* Prepare the device tree */
20153bbf37f2SAndreas Färber     spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size,
201616457e7fSBenjamin Herrenschmidt                                             kernel_size, kernel_le,
201731fe14d1SNathan Fontenot                                             kernel_cmdline,
201831fe14d1SNathan Fontenot                                             spapr->check_exception_irq);
201953018216SPaolo Bonzini     assert(spapr->fdt_skel != NULL);
20205b2128d2SAlexander Graf 
202146503c2bSMichael Roth     /* used by RTAS */
202246503c2bSMichael Roth     QTAILQ_INIT(&spapr->ccs_list);
202346503c2bSMichael Roth     qemu_register_reset(spapr_ccs_reset_hook, spapr);
202446503c2bSMichael Roth 
20255b2128d2SAlexander Graf     qemu_register_boot_set(spapr_boot_set, spapr);
202653018216SPaolo Bonzini }
202753018216SPaolo Bonzini 
2028135a129aSAneesh Kumar K.V static int spapr_kvm_type(const char *vm_type)
2029135a129aSAneesh Kumar K.V {
2030135a129aSAneesh Kumar K.V     if (!vm_type) {
2031135a129aSAneesh Kumar K.V         return 0;
2032135a129aSAneesh Kumar K.V     }
2033135a129aSAneesh Kumar K.V 
2034135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "HV")) {
2035135a129aSAneesh Kumar K.V         return 1;
2036135a129aSAneesh Kumar K.V     }
2037135a129aSAneesh Kumar K.V 
2038135a129aSAneesh Kumar K.V     if (!strcmp(vm_type, "PR")) {
2039135a129aSAneesh Kumar K.V         return 2;
2040135a129aSAneesh Kumar K.V     }
2041135a129aSAneesh Kumar K.V 
2042135a129aSAneesh Kumar K.V     error_report("Unknown kvm-type specified '%s'", vm_type);
2043135a129aSAneesh Kumar K.V     exit(1);
2044135a129aSAneesh Kumar K.V }
2045135a129aSAneesh Kumar K.V 
204671461b0fSAlexey Kardashevskiy /*
2047627b84f4SGonglei  * Implementation of an interface to adjust firmware path
204871461b0fSAlexey Kardashevskiy  * for the bootindex property handling.
204971461b0fSAlexey Kardashevskiy  */
205071461b0fSAlexey Kardashevskiy static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
205171461b0fSAlexey Kardashevskiy                                    DeviceState *dev)
205271461b0fSAlexey Kardashevskiy {
205371461b0fSAlexey Kardashevskiy #define CAST(type, obj, name) \
205471461b0fSAlexey Kardashevskiy     ((type *)object_dynamic_cast(OBJECT(obj), (name)))
205571461b0fSAlexey Kardashevskiy     SCSIDevice *d = CAST(SCSIDevice,  dev, TYPE_SCSI_DEVICE);
205671461b0fSAlexey Kardashevskiy     sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
205771461b0fSAlexey Kardashevskiy 
205871461b0fSAlexey Kardashevskiy     if (d) {
205971461b0fSAlexey Kardashevskiy         void *spapr = CAST(void, bus->parent, "spapr-vscsi");
206071461b0fSAlexey Kardashevskiy         VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
206171461b0fSAlexey Kardashevskiy         USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
206271461b0fSAlexey Kardashevskiy 
206371461b0fSAlexey Kardashevskiy         if (spapr) {
206471461b0fSAlexey Kardashevskiy             /*
206571461b0fSAlexey Kardashevskiy              * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
206671461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
206771461b0fSAlexey Kardashevskiy              * in the top 16 bits of the 64-bit LUN
206871461b0fSAlexey Kardashevskiy              */
206971461b0fSAlexey Kardashevskiy             unsigned id = 0x8000 | (d->id << 8) | d->lun;
207071461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
207171461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 48);
207271461b0fSAlexey Kardashevskiy         } else if (virtio) {
207371461b0fSAlexey Kardashevskiy             /*
207471461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (target << 8) | lun
207571461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
207671461b0fSAlexey Kardashevskiy              * Note: the quote above is from SLOF and it is wrong,
207771461b0fSAlexey Kardashevskiy              * the actual binding is:
207871461b0fSAlexey Kardashevskiy              * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
207971461b0fSAlexey Kardashevskiy              */
208071461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (d->id << 16) | d->lun;
208171461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
208271461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
208371461b0fSAlexey Kardashevskiy         } else if (usb) {
208471461b0fSAlexey Kardashevskiy             /*
208571461b0fSAlexey Kardashevskiy              * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
208671461b0fSAlexey Kardashevskiy              * in the top 32 bits of the 64-bit LUN
208771461b0fSAlexey Kardashevskiy              */
208871461b0fSAlexey Kardashevskiy             unsigned usb_port = atoi(usb->port->path);
208971461b0fSAlexey Kardashevskiy             unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
209071461b0fSAlexey Kardashevskiy             return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
209171461b0fSAlexey Kardashevskiy                                    (uint64_t)id << 32);
209271461b0fSAlexey Kardashevskiy         }
209371461b0fSAlexey Kardashevskiy     }
209471461b0fSAlexey Kardashevskiy 
209571461b0fSAlexey Kardashevskiy     if (phb) {
209671461b0fSAlexey Kardashevskiy         /* Replace "pci" with "pci@800000020000000" */
209771461b0fSAlexey Kardashevskiy         return g_strdup_printf("pci@%"PRIX64, phb->buid);
209871461b0fSAlexey Kardashevskiy     }
209971461b0fSAlexey Kardashevskiy 
210071461b0fSAlexey Kardashevskiy     return NULL;
210171461b0fSAlexey Kardashevskiy }
210271461b0fSAlexey Kardashevskiy 
210323825581SEduardo Habkost static char *spapr_get_kvm_type(Object *obj, Error **errp)
210423825581SEduardo Habkost {
210528e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
210623825581SEduardo Habkost 
210728e02042SDavid Gibson     return g_strdup(spapr->kvm_type);
210823825581SEduardo Habkost }
210923825581SEduardo Habkost 
211023825581SEduardo Habkost static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
211123825581SEduardo Habkost {
211228e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
211323825581SEduardo Habkost 
211428e02042SDavid Gibson     g_free(spapr->kvm_type);
211528e02042SDavid Gibson     spapr->kvm_type = g_strdup(value);
211623825581SEduardo Habkost }
211723825581SEduardo Habkost 
211823825581SEduardo Habkost static void spapr_machine_initfn(Object *obj)
211923825581SEduardo Habkost {
2120715c5407SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
2121715c5407SDavid Gibson 
2122715c5407SDavid Gibson     spapr->htab_fd = -1;
212323825581SEduardo Habkost     object_property_add_str(obj, "kvm-type",
212423825581SEduardo Habkost                             spapr_get_kvm_type, spapr_set_kvm_type, NULL);
212549d2e648SMarcel Apfelbaum     object_property_set_description(obj, "kvm-type",
212649d2e648SMarcel Apfelbaum                                     "Specifies the KVM virtualization mode (HV, PR)",
212749d2e648SMarcel Apfelbaum                                     NULL);
212823825581SEduardo Habkost }
212923825581SEduardo Habkost 
213087bbdd9cSDavid Gibson static void spapr_machine_finalizefn(Object *obj)
213187bbdd9cSDavid Gibson {
213287bbdd9cSDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
213387bbdd9cSDavid Gibson 
213487bbdd9cSDavid Gibson     g_free(spapr->kvm_type);
213587bbdd9cSDavid Gibson }
213687bbdd9cSDavid Gibson 
2137*e0eeb4a2SAlex Bennée static void ppc_cpu_do_nmi_on_cpu(CPUState *cs, void *arg)
213834316482SAlexey Kardashevskiy {
213934316482SAlexey Kardashevskiy     cpu_synchronize_state(cs);
214034316482SAlexey Kardashevskiy     ppc_cpu_do_system_reset(cs);
214134316482SAlexey Kardashevskiy }
214234316482SAlexey Kardashevskiy 
214334316482SAlexey Kardashevskiy static void spapr_nmi(NMIState *n, int cpu_index, Error **errp)
214434316482SAlexey Kardashevskiy {
214534316482SAlexey Kardashevskiy     CPUState *cs;
214634316482SAlexey Kardashevskiy 
214734316482SAlexey Kardashevskiy     CPU_FOREACH(cs) {
2148*e0eeb4a2SAlex Bennée         async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, NULL);
214934316482SAlexey Kardashevskiy     }
215034316482SAlexey Kardashevskiy }
215134316482SAlexey Kardashevskiy 
2152c20d332aSBharata B Rao static void spapr_add_lmbs(DeviceState *dev, uint64_t addr, uint64_t size,
2153c20d332aSBharata B Rao                            uint32_t node, Error **errp)
2154c20d332aSBharata B Rao {
2155c20d332aSBharata B Rao     sPAPRDRConnector *drc;
2156c20d332aSBharata B Rao     sPAPRDRConnectorClass *drck;
2157c20d332aSBharata B Rao     uint32_t nr_lmbs = size/SPAPR_MEMORY_BLOCK_SIZE;
2158c20d332aSBharata B Rao     int i, fdt_offset, fdt_size;
2159c20d332aSBharata B Rao     void *fdt;
2160c20d332aSBharata B Rao 
2161c20d332aSBharata B Rao     for (i = 0; i < nr_lmbs; i++) {
2162c20d332aSBharata B Rao         drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
2163c20d332aSBharata B Rao                 addr/SPAPR_MEMORY_BLOCK_SIZE);
2164c20d332aSBharata B Rao         g_assert(drc);
2165c20d332aSBharata B Rao 
2166c20d332aSBharata B Rao         fdt = create_device_tree(&fdt_size);
2167c20d332aSBharata B Rao         fdt_offset = spapr_populate_memory_node(fdt, node, addr,
2168c20d332aSBharata B Rao                                                 SPAPR_MEMORY_BLOCK_SIZE);
2169c20d332aSBharata B Rao 
2170c20d332aSBharata B Rao         drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
2171c20d332aSBharata B Rao         drck->attach(drc, dev, fdt, fdt_offset, !dev->hotplugged, errp);
2172c20d332aSBharata B Rao         addr += SPAPR_MEMORY_BLOCK_SIZE;
2173c20d332aSBharata B Rao     }
21745dd5238cSJianjun Duan     /* send hotplug notification to the
21755dd5238cSJianjun Duan      * guest only in case of hotplugged memory
21765dd5238cSJianjun Duan      */
21775dd5238cSJianjun Duan     if (dev->hotplugged) {
21780a417869SBharata B Rao        spapr_hotplug_req_add_by_count(SPAPR_DR_CONNECTOR_TYPE_LMB, nr_lmbs);
2179c20d332aSBharata B Rao     }
21805dd5238cSJianjun Duan }
2181c20d332aSBharata B Rao 
2182c20d332aSBharata B Rao static void spapr_memory_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
2183c20d332aSBharata B Rao                               uint32_t node, Error **errp)
2184c20d332aSBharata B Rao {
2185c20d332aSBharata B Rao     Error *local_err = NULL;
2186c20d332aSBharata B Rao     sPAPRMachineState *ms = SPAPR_MACHINE(hotplug_dev);
2187c20d332aSBharata B Rao     PCDIMMDevice *dimm = PC_DIMM(dev);
2188c20d332aSBharata B Rao     PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
2189c20d332aSBharata B Rao     MemoryRegion *mr = ddc->get_memory_region(dimm);
2190c20d332aSBharata B Rao     uint64_t align = memory_region_get_alignment(mr);
2191c20d332aSBharata B Rao     uint64_t size = memory_region_size(mr);
2192c20d332aSBharata B Rao     uint64_t addr;
2193c20d332aSBharata B Rao 
2194c20d332aSBharata B Rao     if (size % SPAPR_MEMORY_BLOCK_SIZE) {
2195c20d332aSBharata B Rao         error_setg(&local_err, "Hotplugged memory size must be a multiple of "
2196c20d332aSBharata B Rao                       "%lld MB", SPAPR_MEMORY_BLOCK_SIZE/M_BYTE);
2197c20d332aSBharata B Rao         goto out;
2198c20d332aSBharata B Rao     }
2199c20d332aSBharata B Rao 
2200d6a9b0b8SMichael S. Tsirkin     pc_dimm_memory_plug(dev, &ms->hotplug_memory, mr, align, &local_err);
2201c20d332aSBharata B Rao     if (local_err) {
2202c20d332aSBharata B Rao         goto out;
2203c20d332aSBharata B Rao     }
2204c20d332aSBharata B Rao 
2205c20d332aSBharata B Rao     addr = object_property_get_int(OBJECT(dimm), PC_DIMM_ADDR_PROP, &local_err);
2206c20d332aSBharata B Rao     if (local_err) {
2207c20d332aSBharata B Rao         pc_dimm_memory_unplug(dev, &ms->hotplug_memory, mr);
2208c20d332aSBharata B Rao         goto out;
2209c20d332aSBharata B Rao     }
2210c20d332aSBharata B Rao 
2211c20d332aSBharata B Rao     spapr_add_lmbs(dev, addr, size, node, &error_abort);
2212c20d332aSBharata B Rao 
2213c20d332aSBharata B Rao out:
2214c20d332aSBharata B Rao     error_propagate(errp, local_err);
2215c20d332aSBharata B Rao }
2216c20d332aSBharata B Rao 
2217af81cf32SBharata B Rao void *spapr_populate_hotplug_cpu_dt(CPUState *cs, int *fdt_offset,
2218af81cf32SBharata B Rao                                     sPAPRMachineState *spapr)
2219af81cf32SBharata B Rao {
2220af81cf32SBharata B Rao     PowerPCCPU *cpu = POWERPC_CPU(cs);
2221af81cf32SBharata B Rao     DeviceClass *dc = DEVICE_GET_CLASS(cs);
2222af81cf32SBharata B Rao     int id = ppc_get_vcpu_dt_id(cpu);
2223af81cf32SBharata B Rao     void *fdt;
2224af81cf32SBharata B Rao     int offset, fdt_size;
2225af81cf32SBharata B Rao     char *nodename;
2226af81cf32SBharata B Rao 
2227af81cf32SBharata B Rao     fdt = create_device_tree(&fdt_size);
2228af81cf32SBharata B Rao     nodename = g_strdup_printf("%s@%x", dc->fw_name, id);
2229af81cf32SBharata B Rao     offset = fdt_add_subnode(fdt, 0, nodename);
2230af81cf32SBharata B Rao 
2231af81cf32SBharata B Rao     spapr_populate_cpu_dt(cs, fdt, offset, spapr);
2232af81cf32SBharata B Rao     g_free(nodename);
2233af81cf32SBharata B Rao 
2234af81cf32SBharata B Rao     *fdt_offset = offset;
2235af81cf32SBharata B Rao     return fdt;
2236af81cf32SBharata B Rao }
2237af81cf32SBharata B Rao 
2238c20d332aSBharata B Rao static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
2239c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
2240c20d332aSBharata B Rao {
2241c20d332aSBharata B Rao     sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(qdev_get_machine());
2242c20d332aSBharata B Rao 
2243c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
2244b556854bSBharata B Rao         int node;
2245c20d332aSBharata B Rao 
2246c20d332aSBharata B Rao         if (!smc->dr_lmb_enabled) {
2247c20d332aSBharata B Rao             error_setg(errp, "Memory hotplug not supported for this machine");
2248c20d332aSBharata B Rao             return;
2249c20d332aSBharata B Rao         }
2250c20d332aSBharata B Rao         node = object_property_get_int(OBJECT(dev), PC_DIMM_NODE_PROP, errp);
2251c20d332aSBharata B Rao         if (*errp) {
2252c20d332aSBharata B Rao             return;
2253c20d332aSBharata B Rao         }
22541a5512bbSGonglei         if (node < 0 || node >= MAX_NODES) {
22551a5512bbSGonglei             error_setg(errp, "Invaild node %d", node);
22561a5512bbSGonglei             return;
22571a5512bbSGonglei         }
2258c20d332aSBharata B Rao 
2259b556854bSBharata B Rao         /*
2260b556854bSBharata B Rao          * Currently PowerPC kernel doesn't allow hot-adding memory to
2261b556854bSBharata B Rao          * memory-less node, but instead will silently add the memory
2262b556854bSBharata B Rao          * to the first node that has some memory. This causes two
2263b556854bSBharata B Rao          * unexpected behaviours for the user.
2264b556854bSBharata B Rao          *
2265b556854bSBharata B Rao          * - Memory gets hotplugged to a different node than what the user
2266b556854bSBharata B Rao          *   specified.
2267b556854bSBharata B Rao          * - Since pc-dimm subsystem in QEMU still thinks that memory belongs
2268b556854bSBharata B Rao          *   to memory-less node, a reboot will set things accordingly
2269b556854bSBharata B Rao          *   and the previously hotplugged memory now ends in the right node.
2270b556854bSBharata B Rao          *   This appears as if some memory moved from one node to another.
2271b556854bSBharata B Rao          *
2272b556854bSBharata B Rao          * So until kernel starts supporting memory hotplug to memory-less
2273b556854bSBharata B Rao          * nodes, just prevent such attempts upfront in QEMU.
2274b556854bSBharata B Rao          */
2275b556854bSBharata B Rao         if (nb_numa_nodes && !numa_info[node].node_mem) {
2276b556854bSBharata B Rao             error_setg(errp, "Can't hotplug memory to memory-less node %d",
2277b556854bSBharata B Rao                        node);
2278b556854bSBharata B Rao             return;
2279b556854bSBharata B Rao         }
2280b556854bSBharata B Rao 
2281c20d332aSBharata B Rao         spapr_memory_plug(hotplug_dev, dev, node, errp);
2282af81cf32SBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
2283af81cf32SBharata B Rao         spapr_core_plug(hotplug_dev, dev, errp);
2284c20d332aSBharata B Rao     }
2285c20d332aSBharata B Rao }
2286c20d332aSBharata B Rao 
2287c20d332aSBharata B Rao static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
2288c20d332aSBharata B Rao                                       DeviceState *dev, Error **errp)
2289c20d332aSBharata B Rao {
22903c0c47e3SDavid Gibson     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
22916f4b5c3eSBharata B Rao 
2292c20d332aSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
2293c20d332aSBharata B Rao         error_setg(errp, "Memory hot unplug not supported by sPAPR");
22946f4b5c3eSBharata B Rao     } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
22953c0c47e3SDavid Gibson         if (!mc->query_hotpluggable_cpus) {
22966f4b5c3eSBharata B Rao             error_setg(errp, "CPU hot unplug not supported on this machine");
22976f4b5c3eSBharata B Rao             return;
22986f4b5c3eSBharata B Rao         }
22996f4b5c3eSBharata B Rao         spapr_core_unplug(hotplug_dev, dev, errp);
2300c20d332aSBharata B Rao     }
2301c20d332aSBharata B Rao }
2302c20d332aSBharata B Rao 
230394a94e4cSBharata B Rao static void spapr_machine_device_pre_plug(HotplugHandler *hotplug_dev,
230494a94e4cSBharata B Rao                                           DeviceState *dev, Error **errp)
230594a94e4cSBharata B Rao {
230694a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
230794a94e4cSBharata B Rao         spapr_core_pre_plug(hotplug_dev, dev, errp);
230894a94e4cSBharata B Rao     }
230994a94e4cSBharata B Rao }
231094a94e4cSBharata B Rao 
23117ebaf795SBharata B Rao static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
2312c20d332aSBharata B Rao                                                  DeviceState *dev)
2313c20d332aSBharata B Rao {
231494a94e4cSBharata B Rao     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
231594a94e4cSBharata B Rao         object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE)) {
2316c20d332aSBharata B Rao         return HOTPLUG_HANDLER(machine);
2317c20d332aSBharata B Rao     }
2318c20d332aSBharata B Rao     return NULL;
2319c20d332aSBharata B Rao }
2320c20d332aSBharata B Rao 
232120bb648dSDavid Gibson static unsigned spapr_cpu_index_to_socket_id(unsigned cpu_index)
232220bb648dSDavid Gibson {
232320bb648dSDavid Gibson     /* Allocate to NUMA nodes on a "socket" basis (not that concept of
232420bb648dSDavid Gibson      * socket means much for the paravirtualized PAPR platform) */
232520bb648dSDavid Gibson     return cpu_index / smp_threads / smp_cores;
232620bb648dSDavid Gibson }
232720bb648dSDavid Gibson 
23282474bfd4SIgor Mammedov static HotpluggableCPUList *spapr_query_hotpluggable_cpus(MachineState *machine)
23292474bfd4SIgor Mammedov {
23302474bfd4SIgor Mammedov     int i;
23312474bfd4SIgor Mammedov     HotpluggableCPUList *head = NULL;
23322474bfd4SIgor Mammedov     sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
23332474bfd4SIgor Mammedov     int spapr_max_cores = max_cpus / smp_threads;
23342474bfd4SIgor Mammedov 
23352474bfd4SIgor Mammedov     for (i = 0; i < spapr_max_cores; i++) {
23362474bfd4SIgor Mammedov         HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
23372474bfd4SIgor Mammedov         HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
23382474bfd4SIgor Mammedov         CpuInstanceProperties *cpu_props = g_new0(typeof(*cpu_props), 1);
23392474bfd4SIgor Mammedov 
23402474bfd4SIgor Mammedov         cpu_item->type = spapr_get_cpu_core_type(machine->cpu_model);
23412474bfd4SIgor Mammedov         cpu_item->vcpus_count = smp_threads;
234227393c33SPeter Krempa         cpu_props->has_core_id = true;
234312bf2d33SGreg Kurz         cpu_props->core_id = i * smp_threads;
23442474bfd4SIgor Mammedov         /* TODO: add 'has_node/node' here to describe
23452474bfd4SIgor Mammedov            to which node core belongs */
23462474bfd4SIgor Mammedov 
23472474bfd4SIgor Mammedov         cpu_item->props = cpu_props;
23482474bfd4SIgor Mammedov         if (spapr->cores[i]) {
23492474bfd4SIgor Mammedov             cpu_item->has_qom_path = true;
23502474bfd4SIgor Mammedov             cpu_item->qom_path = object_get_canonical_path(spapr->cores[i]);
23512474bfd4SIgor Mammedov         }
23522474bfd4SIgor Mammedov         list_item->value = cpu_item;
23532474bfd4SIgor Mammedov         list_item->next = head;
23542474bfd4SIgor Mammedov         head = list_item;
23552474bfd4SIgor Mammedov     }
23562474bfd4SIgor Mammedov     return head;
23572474bfd4SIgor Mammedov }
23582474bfd4SIgor Mammedov 
235929ee3247SAlexey Kardashevskiy static void spapr_machine_class_init(ObjectClass *oc, void *data)
236053018216SPaolo Bonzini {
236129ee3247SAlexey Kardashevskiy     MachineClass *mc = MACHINE_CLASS(oc);
2362224245bfSDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(oc);
236371461b0fSAlexey Kardashevskiy     FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
236434316482SAlexey Kardashevskiy     NMIClass *nc = NMI_CLASS(oc);
2365c20d332aSBharata B Rao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
236629ee3247SAlexey Kardashevskiy 
23670eb9054cSDavid Gibson     mc->desc = "pSeries Logical Partition (PAPR compliant)";
2368fc9f38c3SDavid Gibson 
2369fc9f38c3SDavid Gibson     /*
2370fc9f38c3SDavid Gibson      * We set up the default / latest behaviour here.  The class_init
2371fc9f38c3SDavid Gibson      * functions for the specific versioned machine types can override
2372fc9f38c3SDavid Gibson      * these details for backwards compatibility
2373fc9f38c3SDavid Gibson      */
2374958db90cSMarcel Apfelbaum     mc->init = ppc_spapr_init;
2375958db90cSMarcel Apfelbaum     mc->reset = ppc_spapr_reset;
2376958db90cSMarcel Apfelbaum     mc->block_default_type = IF_SCSI;
237738b02bd8SAlexey Kardashevskiy     mc->max_cpus = MAX_CPUMASK_BITS;
2378958db90cSMarcel Apfelbaum     mc->no_parallel = 1;
23795b2128d2SAlexander Graf     mc->default_boot_order = "";
2380a34944feSNikunj A Dadhania     mc->default_ram_size = 512 * M_BYTE;
2381958db90cSMarcel Apfelbaum     mc->kvm_type = spapr_kvm_type;
23829e3f9733SAlexander Graf     mc->has_dynamic_sysbus = true;
2383e4024630SLaurent Vivier     mc->pci_allow_0_address = true;
23847ebaf795SBharata B Rao     mc->get_hotplug_handler = spapr_get_hotplug_handler;
238594a94e4cSBharata B Rao     hc->pre_plug = spapr_machine_device_pre_plug;
2386c20d332aSBharata B Rao     hc->plug = spapr_machine_device_plug;
2387c20d332aSBharata B Rao     hc->unplug = spapr_machine_device_unplug;
238820bb648dSDavid Gibson     mc->cpu_index_to_socket_id = spapr_cpu_index_to_socket_id;
238900b4fbe2SMarcel Apfelbaum 
2390fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = true;
23913c0c47e3SDavid Gibson     mc->query_hotpluggable_cpus = spapr_query_hotpluggable_cpus;
239271461b0fSAlexey Kardashevskiy     fwc->get_dev_path = spapr_get_fw_dev_path;
239334316482SAlexey Kardashevskiy     nc->nmi_monitor_handler = spapr_nmi;
239453018216SPaolo Bonzini }
239553018216SPaolo Bonzini 
239629ee3247SAlexey Kardashevskiy static const TypeInfo spapr_machine_info = {
239729ee3247SAlexey Kardashevskiy     .name          = TYPE_SPAPR_MACHINE,
239829ee3247SAlexey Kardashevskiy     .parent        = TYPE_MACHINE,
23994aee7362SDavid Gibson     .abstract      = true,
24006ca1502eSAlexey Kardashevskiy     .instance_size = sizeof(sPAPRMachineState),
240123825581SEduardo Habkost     .instance_init = spapr_machine_initfn,
240287bbdd9cSDavid Gibson     .instance_finalize = spapr_machine_finalizefn,
2403183930c0SDavid Gibson     .class_size    = sizeof(sPAPRMachineClass),
240429ee3247SAlexey Kardashevskiy     .class_init    = spapr_machine_class_init,
240571461b0fSAlexey Kardashevskiy     .interfaces = (InterfaceInfo[]) {
240671461b0fSAlexey Kardashevskiy         { TYPE_FW_PATH_PROVIDER },
240734316482SAlexey Kardashevskiy         { TYPE_NMI },
2408c20d332aSBharata B Rao         { TYPE_HOTPLUG_HANDLER },
240971461b0fSAlexey Kardashevskiy         { }
241071461b0fSAlexey Kardashevskiy     },
241129ee3247SAlexey Kardashevskiy };
241229ee3247SAlexey Kardashevskiy 
2413fccbc785SDavid Gibson #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest)                 \
24145013c547SDavid Gibson     static void spapr_machine_##suffix##_class_init(ObjectClass *oc, \
24155013c547SDavid Gibson                                                     void *data)      \
24165013c547SDavid Gibson     {                                                                \
24175013c547SDavid Gibson         MachineClass *mc = MACHINE_CLASS(oc);                        \
24185013c547SDavid Gibson         spapr_machine_##suffix##_class_options(mc);                  \
2419fccbc785SDavid Gibson         if (latest) {                                                \
2420fccbc785SDavid Gibson             mc->alias = "pseries";                                   \
2421fccbc785SDavid Gibson             mc->is_default = 1;                                      \
2422fccbc785SDavid Gibson         }                                                            \
24235013c547SDavid Gibson     }                                                                \
24245013c547SDavid Gibson     static void spapr_machine_##suffix##_instance_init(Object *obj)  \
24255013c547SDavid Gibson     {                                                                \
24265013c547SDavid Gibson         MachineState *machine = MACHINE(obj);                        \
24275013c547SDavid Gibson         spapr_machine_##suffix##_instance_options(machine);          \
24285013c547SDavid Gibson     }                                                                \
24295013c547SDavid Gibson     static const TypeInfo spapr_machine_##suffix##_info = {          \
24305013c547SDavid Gibson         .name = MACHINE_TYPE_NAME("pseries-" verstr),                \
24315013c547SDavid Gibson         .parent = TYPE_SPAPR_MACHINE,                                \
24325013c547SDavid Gibson         .class_init = spapr_machine_##suffix##_class_init,           \
24335013c547SDavid Gibson         .instance_init = spapr_machine_##suffix##_instance_init,     \
24345013c547SDavid Gibson     };                                                               \
24355013c547SDavid Gibson     static void spapr_machine_register_##suffix(void)                \
24365013c547SDavid Gibson     {                                                                \
24375013c547SDavid Gibson         type_register(&spapr_machine_##suffix##_info);               \
24385013c547SDavid Gibson     }                                                                \
24390e6aac87SEduardo Habkost     type_init(spapr_machine_register_##suffix)
24405013c547SDavid Gibson 
24411c5f29bbSDavid Gibson /*
24421ea1eefcSBharata B Rao  * pseries-2.7
24431ea1eefcSBharata B Rao  */
24441ea1eefcSBharata B Rao static void spapr_machine_2_7_instance_options(MachineState *machine)
24451ea1eefcSBharata B Rao {
24461ea1eefcSBharata B Rao }
24471ea1eefcSBharata B Rao 
24481ea1eefcSBharata B Rao static void spapr_machine_2_7_class_options(MachineClass *mc)
24491ea1eefcSBharata B Rao {
24501ea1eefcSBharata B Rao     /* Defaults for the latest behaviour inherited from the base class */
24511ea1eefcSBharata B Rao }
24521ea1eefcSBharata B Rao 
24531ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_7, "2.7", true);
24541ea1eefcSBharata B Rao 
24551ea1eefcSBharata B Rao /*
24564b23699cSDavid Gibson  * pseries-2.6
24574b23699cSDavid Gibson  */
24581ea1eefcSBharata B Rao #define SPAPR_COMPAT_2_6 \
2459ae4de14cSAlexey Kardashevskiy     HW_COMPAT_2_6 \
2460ae4de14cSAlexey Kardashevskiy     { \
2461ae4de14cSAlexey Kardashevskiy         .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,\
2462ae4de14cSAlexey Kardashevskiy         .property = "ddw",\
2463ae4de14cSAlexey Kardashevskiy         .value    = stringify(off),\
2464ae4de14cSAlexey Kardashevskiy     },
24651ea1eefcSBharata B Rao 
24664b23699cSDavid Gibson static void spapr_machine_2_6_instance_options(MachineState *machine)
24674b23699cSDavid Gibson {
24684b23699cSDavid Gibson }
24694b23699cSDavid Gibson 
24704b23699cSDavid Gibson static void spapr_machine_2_6_class_options(MachineClass *mc)
24714b23699cSDavid Gibson {
24721ea1eefcSBharata B Rao     spapr_machine_2_7_class_options(mc);
24733c0c47e3SDavid Gibson     mc->query_hotpluggable_cpus = NULL;
24741ea1eefcSBharata B Rao     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_6);
24754b23699cSDavid Gibson }
24764b23699cSDavid Gibson 
24771ea1eefcSBharata B Rao DEFINE_SPAPR_MACHINE(2_6, "2.6", false);
24784b23699cSDavid Gibson 
24794b23699cSDavid Gibson /*
24801c5f29bbSDavid Gibson  * pseries-2.5
24811c5f29bbSDavid Gibson  */
24824b23699cSDavid Gibson #define SPAPR_COMPAT_2_5 \
248357c522f4SThomas Huth     HW_COMPAT_2_5 \
248457c522f4SThomas Huth     { \
248557c522f4SThomas Huth         .driver   = "spapr-vlan", \
248657c522f4SThomas Huth         .property = "use-rx-buffer-pools", \
248757c522f4SThomas Huth         .value    = "off", \
248857c522f4SThomas Huth     },
24894b23699cSDavid Gibson 
24905013c547SDavid Gibson static void spapr_machine_2_5_instance_options(MachineState *machine)
24911c5f29bbSDavid Gibson {
24925013c547SDavid Gibson }
24935013c547SDavid Gibson 
24945013c547SDavid Gibson static void spapr_machine_2_5_class_options(MachineClass *mc)
24955013c547SDavid Gibson {
249657040d45SThomas Huth     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
249757040d45SThomas Huth 
24984b23699cSDavid Gibson     spapr_machine_2_6_class_options(mc);
249957040d45SThomas Huth     smc->use_ohci_by_default = true;
25004b23699cSDavid Gibson     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_5);
25011c5f29bbSDavid Gibson }
25021c5f29bbSDavid Gibson 
25034b23699cSDavid Gibson DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
25041c5f29bbSDavid Gibson 
25051c5f29bbSDavid Gibson /*
25061c5f29bbSDavid Gibson  * pseries-2.4
25071c5f29bbSDavid Gibson  */
250880fd50f9SCornelia Huck #define SPAPR_COMPAT_2_4 \
250980fd50f9SCornelia Huck         HW_COMPAT_2_4
251080fd50f9SCornelia Huck 
25115013c547SDavid Gibson static void spapr_machine_2_4_instance_options(MachineState *machine)
25121c5f29bbSDavid Gibson {
25135013c547SDavid Gibson     spapr_machine_2_5_instance_options(machine);
25145013c547SDavid Gibson }
25151c5f29bbSDavid Gibson 
25165013c547SDavid Gibson static void spapr_machine_2_4_class_options(MachineClass *mc)
25175013c547SDavid Gibson {
2518fc9f38c3SDavid Gibson     sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
2519fc9f38c3SDavid Gibson 
2520fc9f38c3SDavid Gibson     spapr_machine_2_5_class_options(mc);
2521fc9f38c3SDavid Gibson     smc->dr_lmb_enabled = false;
2522f949b4e5SDavid Gibson     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_4);
25231c5f29bbSDavid Gibson }
25241c5f29bbSDavid Gibson 
2525fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
25261c5f29bbSDavid Gibson 
25271c5f29bbSDavid Gibson /*
25281c5f29bbSDavid Gibson  * pseries-2.3
25291c5f29bbSDavid Gibson  */
253038ff32c6SEduardo Habkost #define SPAPR_COMPAT_2_3 \
25317619c7b0SMichael Roth         HW_COMPAT_2_3 \
25327619c7b0SMichael Roth         {\
25337619c7b0SMichael Roth             .driver   = "spapr-pci-host-bridge",\
25347619c7b0SMichael Roth             .property = "dynamic-reconfiguration",\
25357619c7b0SMichael Roth             .value    = "off",\
25367619c7b0SMichael Roth         },
253738ff32c6SEduardo Habkost 
25385013c547SDavid Gibson static void spapr_machine_2_3_instance_options(MachineState *machine)
25391c5f29bbSDavid Gibson {
25405013c547SDavid Gibson     spapr_machine_2_4_instance_options(machine);
25411c5f29bbSDavid Gibson     savevm_skip_section_footers();
25421c5f29bbSDavid Gibson     global_state_set_optional();
254309b5e30dSGreg Kurz     savevm_skip_configuration();
25441c5f29bbSDavid Gibson }
25451c5f29bbSDavid Gibson 
25465013c547SDavid Gibson static void spapr_machine_2_3_class_options(MachineClass *mc)
25471c5f29bbSDavid Gibson {
2548fc9f38c3SDavid Gibson     spapr_machine_2_4_class_options(mc);
2549f949b4e5SDavid Gibson     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_3);
25501c5f29bbSDavid Gibson }
2551fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
25521c5f29bbSDavid Gibson 
25531c5f29bbSDavid Gibson /*
25541c5f29bbSDavid Gibson  * pseries-2.2
25551c5f29bbSDavid Gibson  */
25561c5f29bbSDavid Gibson 
2557b194df47SAlexey Kardashevskiy #define SPAPR_COMPAT_2_2 \
25584dfd8eaaSEduardo Habkost         HW_COMPAT_2_2 \
2559b194df47SAlexey Kardashevskiy         {\
2560b194df47SAlexey Kardashevskiy             .driver   = TYPE_SPAPR_PCI_HOST_BRIDGE,\
2561b194df47SAlexey Kardashevskiy             .property = "mem_win_size",\
2562b194df47SAlexey Kardashevskiy             .value    = "0x20000000",\
2563dd754bafSEduardo Habkost         },
2564b194df47SAlexey Kardashevskiy 
25655013c547SDavid Gibson static void spapr_machine_2_2_instance_options(MachineState *machine)
2566b0e966d0SJason Wang {
25675013c547SDavid Gibson     spapr_machine_2_3_instance_options(machine);
2568cba0e779SGreg Kurz     machine->suppress_vmdesc = true;
2569b0e966d0SJason Wang }
2570b0e966d0SJason Wang 
25715013c547SDavid Gibson static void spapr_machine_2_2_class_options(MachineClass *mc)
2572b0e966d0SJason Wang {
2573fc9f38c3SDavid Gibson     spapr_machine_2_3_class_options(mc);
2574f949b4e5SDavid Gibson     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_2);
25751c5f29bbSDavid Gibson }
2576fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
25771c5f29bbSDavid Gibson 
25781c5f29bbSDavid Gibson /*
25791c5f29bbSDavid Gibson  * pseries-2.1
25801c5f29bbSDavid Gibson  */
25811c5f29bbSDavid Gibson #define SPAPR_COMPAT_2_1 \
25821c5f29bbSDavid Gibson         HW_COMPAT_2_1
25831c5f29bbSDavid Gibson 
25845013c547SDavid Gibson static void spapr_machine_2_1_instance_options(MachineState *machine)
25851c5f29bbSDavid Gibson {
25865013c547SDavid Gibson     spapr_machine_2_2_instance_options(machine);
25871c5f29bbSDavid Gibson }
25881c5f29bbSDavid Gibson 
25895013c547SDavid Gibson static void spapr_machine_2_1_class_options(MachineClass *mc)
2590b0e966d0SJason Wang {
2591fc9f38c3SDavid Gibson     spapr_machine_2_2_class_options(mc);
2592f949b4e5SDavid Gibson     SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_1);
25936026db45SAlexey Kardashevskiy }
2594fccbc785SDavid Gibson DEFINE_SPAPR_MACHINE(2_1, "2.1", false);
25956026db45SAlexey Kardashevskiy 
259629ee3247SAlexey Kardashevskiy static void spapr_machine_register_types(void)
259729ee3247SAlexey Kardashevskiy {
259829ee3247SAlexey Kardashevskiy     type_register_static(&spapr_machine_info);
259929ee3247SAlexey Kardashevskiy }
260029ee3247SAlexey Kardashevskiy 
260129ee3247SAlexey Kardashevskiy type_init(spapr_machine_register_types)
2602