#include "hw/fw-path-provider.h"
#include "elf.h"
#include "net/net.h"
-#include "sysemu/blockdev.h"
+#include "sysemu/block-backend.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "kvm_ppc.h"
#include "trace.h"
#include "hw/nmi.h"
+#include "hw/compat.h"
+
#include <libfdt.h>
/* SLOF memory layout:
*/
#define FDT_MAX_SIZE 0x40000
#define RTAS_MAX_SIZE 0x10000
+#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
#define FW_OVERHEAD 0x2800000
#define TIMEBASE_FREQ 512000000ULL
-#define MAX_CPUS 256
+#define MAX_CPUS 255
#define PHANDLE_XICP 0x00001111
return (p - prop) * sizeof(uint32_t);
}
+static hwaddr spapr_node0_size(void)
+{
+ if (nb_numa_nodes) {
+ int i;
+ for (i = 0; i < nb_numa_nodes; ++i) {
+ if (numa_info[i].node_mem) {
+ return MIN(pow2floor(numa_info[i].node_mem), ram_size);
+ }
+ }
+ }
+ return ram_size;
+}
+
#define _FDT(exp) \
do { \
int ret = (exp); \
_FDT((fdt_property_string(fdt, "model", "IBM pSeries (emulated by qemu)")));
_FDT((fdt_property_string(fdt, "compatible", "qemu,pseries")));
- if (kvm_enabled()) {
- _FDT((fdt_property_string(fdt, "hypervisor", "kvm")));
- }
-
/*
* Add info to guest to indentify which host is it being run on
* and what is the uuid of the guest
_FDT((fdt_property_cell(fdt, "rtas-error-log-max", RTAS_ERROR_LOG_MAX)));
/*
- * According to PAPR, rtas ibm,os-term, does not gaurantee a return
+ * According to PAPR, rtas ibm,os-term does not guarantee a return
* back to the guest cpu.
*
* While an additional ibm,extended-os-term property indicates that
uint32_t associativity[] = {
cpu_to_be32(0x4), /* length */
cpu_to_be32(0x0), cpu_to_be32(0x0),
- cpu_to_be32(nodeid), cpu_to_be32(nodeid)
+ cpu_to_be32(0x0), cpu_to_be32(nodeid)
};
char mem_name[32];
uint64_t mem_reg_property[2];
/* Update the RMA size if necessary */
if (spapr->vrma_adjust) {
- hwaddr node0_size = (nb_numa_nodes > 1) ?
- numa_info[0].node_mem : ram_size;
- spapr->rma_size = kvmppc_rma_size(node0_size, spapr->htab_shift);
+ spapr->rma_size = kvmppc_rma_size(spapr_node0_size(),
+ spapr->htab_shift);
}
}
+static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
+{
+ bool matched = false;
+
+ if (object_dynamic_cast(OBJECT(sbdev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
+ matched = true;
+ }
+
+ if (!matched) {
+ error_report("Device %s is not supported by this machine yet.",
+ qdev_fw_name(DEVICE(sbdev)));
+ exit(1);
+ }
+
+ return 0;
+}
+
static void ppc_spapr_reset(void)
{
PowerPCCPU *first_ppc_cpu;
+ uint32_t rtas_limit;
+
+ /* Check for unknown sysbus devices */
+ foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL);
/* Reset the hash table & recalc the RMA */
spapr_reset_htab(spapr);
qemu_devices_reset();
+ /*
+ * We place the device tree and RTAS just below either the top of the RMA,
+ * or just below 2GB, whichever is lowere, so that it can be
+ * processed with 32-bit real mode code if necessary
+ */
+ rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR);
+ spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
+ spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
+
/* Load the fdt */
spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr,
spapr->rtas_size);
+ /* Copy RTAS over */
+ cpu_physical_memory_write(spapr->rtas_addr, spapr->rtas_blob,
+ spapr->rtas_size);
+
/* Set up the entry state */
first_ppc_cpu = POWERPC_CPU(first_cpu);
first_ppc_cpu->env.gpr[3] = spapr->fdt_addr;
DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
if (dinfo) {
- qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
+ qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(dinfo));
}
qdev_init_nofail(dev);
MemoryRegion *rma_region;
void *rma = NULL;
hwaddr rma_alloc_size;
- hwaddr node0_size = (nb_numa_nodes > 1) ? numa_info[0].node_mem : ram_size;
+ hwaddr node0_size = spapr_node0_size();
uint32_t initrd_base = 0;
long kernel_size = 0, initrd_size = 0;
- long load_limit, rtas_limit, fw_size;
+ long load_limit, fw_size;
bool kernel_le = false;
char *filename;
exit(1);
}
- /* We place the device tree and RTAS just below either the top of the RMA,
- * or just below 2GB, whichever is lowere, so that it can be
- * processed with 32-bit real mode code if necessary */
- rtas_limit = MIN(spapr->rma_size, 0x80000000);
- spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
- spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
- load_limit = spapr->fdt_addr - FW_OVERHEAD;
+ /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */
+ load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
/* We aim for a hash table of size 1/128 the size of RAM. The
* normal rule of thumb is 1/64 the size of RAM, but that's much
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
- spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
- rtas_limit - spapr->rtas_addr);
- if (spapr->rtas_size < 0) {
+ spapr->rtas_size = get_image_size(filename);
+ spapr->rtas_blob = g_malloc(spapr->rtas_size);
+ if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
exit(1);
}
if (spapr->rtas_size > RTAS_MAX_SIZE) {
- hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
+ hw_error("RTAS too big ! 0x%zx bytes (max is 0x%x)\n",
spapr->rtas_size, RTAS_MAX_SIZE);
exit(1);
}
spapr_create_nvram(spapr);
/* Set up PCI */
- spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
spapr_pci_rtas_init();
phb = spapr_create_phb(spapr, 0);
{
object_property_add_str(obj, "kvm-type",
spapr_get_kvm_type, spapr_set_kvm_type, NULL);
+ object_property_set_description(obj, "kvm-type",
+ "Specifies the KVM virtualization mode (HV, PR)",
+ NULL);
}
static void ppc_cpu_do_nmi_on_cpu(void *arg)
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
NMIClass *nc = NMI_CLASS(oc);
- mc->name = "pseries";
- mc->desc = "pSeries Logical Partition (PAPR compliant)";
- mc->is_default = 1;
mc->init = ppc_spapr_init;
mc->reset = ppc_spapr_reset;
mc->block_default_type = IF_SCSI;
mc->no_parallel = 1;
mc->default_boot_order = NULL;
mc->kvm_type = spapr_kvm_type;
+ mc->has_dynamic_sysbus = true;
fwc->get_dev_path = spapr_get_fw_dev_path;
nc->nmi_monitor_handler = spapr_nmi;
static const TypeInfo spapr_machine_info = {
.name = TYPE_SPAPR_MACHINE,
.parent = TYPE_MACHINE,
+ .abstract = true,
.instance_size = sizeof(sPAPRMachineState),
.instance_init = spapr_machine_initfn,
.class_init = spapr_machine_class_init,
static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
+ static GlobalProperty compat_props[] = {
+ HW_COMPAT_2_1,
+ { /* end of list */ }
+ };
mc->name = "pseries-2.1";
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.1";
- mc->is_default = 0;
+ mc->compat_props = compat_props;
}
static const TypeInfo spapr_machine_2_1_info = {
.class_init = spapr_machine_2_1_class_init,
};
+static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = "pseries-2.2";
+ mc->desc = "pSeries Logical Partition (PAPR compliant) v2.2";
+ mc->alias = "pseries";
+ mc->is_default = 1;
+}
+
+static const TypeInfo spapr_machine_2_2_info = {
+ .name = TYPE_SPAPR_MACHINE "2.2",
+ .parent = TYPE_SPAPR_MACHINE,
+ .class_init = spapr_machine_2_2_class_init,
+};
+
static void spapr_machine_register_types(void)
{
type_register_static(&spapr_machine_info);
type_register_static(&spapr_machine_2_1_info);
+ type_register_static(&spapr_machine_2_2_info);
}
type_init(spapr_machine_register_types)