ppc patch queue 2020-03-17
Here's my final pull request for the qemu-5.0 soft freeze. Sorry this is just under the wire - I hit some last minute problems that took a while to fix up and retest. Highlights are: * Numerous fixes for the FWNMI feature * A handful of cleanups to the device tree construction code * Numerous fixes for the spapr-vscsi device * A number of fixes and cleanups for real mode (MMU off) softmmu handling * Fixes for handling of the PAPR RMA * Better handling of hotplug/unplug events during boot * Assorted other fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl5wnnsACgkQbDjKyiDZ s5JdpQ//eY/AOTs09UhvKxt8DN7lC2WyHGxYSncb2Tj2zaJyPPX9p296IDBMw+KX Cafr6LzwLjpcpOyf/EWzg7qYGbNYoYgRWoOkHI/9pHsrIH3ZvhmnyTVQI5CffeEb EDDXJUQo/2sFpAGeODr5zz+zAQUGzt6ZZUxAiQAF9RYc9ohUGD2x5c86Asx6ZTZo /14bd3qnrcy1x+TxDetb1idFxFr2DsdYqpHAi88zHm+UaWzxYrb7kakd+YbqI24N tYryf5SdtGrWAAdF/7nq2PQJFzskx+t0QearU+ruovRydxYbUtBpkr5HauoVuQXR LiV270sDYDS/D1vvQQKzLxkUuvWmbZ0rB+2BAtS1rwq2sOKqYyQEAkTWfGtSXcf8 7fuZm2i1G78MuYGTOLCrF1u0owUB3QYHvt1NUW09GyWS8X3mahtj2fRe1RtPV/5d NL217bcd32fkMoGCg/lFvK9sCQzR6zJGKkJvOGMVW4ahHCLixpjIWabWtdXjfguT UahRPvlX7fzeVT+DISfjqyxwL+THnTvB3CTMWG2cktf0K1ke4SXcQ0mPyksN1NuC QocfPCr1TN2ri8g9dAPwQmOkojnNs9izpIWRYSl3avTJFNseNPxuHQALXj2Y3Y/O EoYxLN+cqPukQ1O3GxEj5QMKe8V/0986mxWnuS/dMohQOoy+zV4= =BPnR -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-5.0-20200317' into staging ppc patch queue 2020-03-17 Here's my final pull request for the qemu-5.0 soft freeze. Sorry this is just under the wire - I hit some last minute problems that took a while to fix up and retest. Highlights are: * Numerous fixes for the FWNMI feature * A handful of cleanups to the device tree construction code * Numerous fixes for the spapr-vscsi device * A number of fixes and cleanups for real mode (MMU off) softmmu handling * Fixes for handling of the PAPR RMA * Better handling of hotplug/unplug events during boot * Assorted other fixes # gpg: Signature made Tue 17 Mar 2020 09:55:07 GMT # gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full] # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full] # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full] # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown] # Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392 * remotes/dgibson/tags/ppc-for-5.0-20200317: (45 commits) pseries: Update SLOF firmware image ppc/spapr: Ignore common "ibm,nmi-interlock" Linux bug ppc/spapr: Implement FWNMI System Reset delivery target/ppc: allow ppc_cpu_do_system_reset to take an alternate vector ppc/spapr: Allow FWNMI on TCG ppc/spapr: Fix FWNMI machine check interrupt delivery ppc/spapr: Add FWNMI System Reset state ppc/spapr: Change FWNMI names ppc/spapr: Fix FWNMI machine check failure handling spapr: Rename DT functions to newer naming convention spapr: Move creation of ibm,architecture-vec-5 property spapr: Move creation of ibm,dynamic-reconfiguration-memory dt node spapr/rtas: Reserve space for RTAS blob and log pseries: Update SLOF firmware image ppc/spapr: Move GPRs setup to one place target/ppc: Fix rlwinm on ppc64 spapr/xive: use SPAPR_IRQ_IPI to define IPI ranges exposed to the guest hw/scsi/spapr_vscsi: Convert debug fprintf() to trace event hw/scsi/spapr_vscsi: Prevent buffer overflow hw/scsi/spapr_vscsi: Do not mix SRP IU size with DMA buffer size ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b319df5537
@ -289,6 +289,13 @@ The RISC-V no MMU cpus have been depcreated. The two CPUs: ``rv32imacu-nommu`` a
|
||||
``rv64imacu-nommu`` should no longer be used. Instead the MMU status can be specified
|
||||
via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs.
|
||||
|
||||
``compat`` property of server class POWER CPUs (since 5.0)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``compat`` property used to set backwards compatibility modes for
|
||||
the processor has been deprecated. The ``max-cpu-compat`` property of
|
||||
the ``pseries`` machine type should be used instead.
|
||||
|
||||
System emulator devices
|
||||
-----------------------
|
||||
|
||||
|
@ -677,8 +677,8 @@ static void spapr_xive_dt(SpaprInterruptController *intc, uint32_t nr_servers,
|
||||
uint64_t timas[2 * 2];
|
||||
/* Interrupt number ranges for the IPIs */
|
||||
uint32_t lisn_ranges[] = {
|
||||
cpu_to_be32(0),
|
||||
cpu_to_be32(nr_servers),
|
||||
cpu_to_be32(SPAPR_IRQ_IPI),
|
||||
cpu_to_be32(SPAPR_IRQ_IPI + nr_servers),
|
||||
};
|
||||
/*
|
||||
* EQ size - the sizes of pages supported by the system 4K, 64K,
|
||||
|
@ -829,7 +829,7 @@ ISABus *pnv_lpc_isa_create(PnvLpcController *lpc, bool use_cpld, Error **errp)
|
||||
bool hostboot_mode = !!pnv->fw_load_addr;
|
||||
|
||||
/* let isa_bus_new() create its own bridge on SysBus otherwise
|
||||
* devices speficied on the command line won't find the bus and
|
||||
* devices specified on the command line won't find the bus and
|
||||
* will fail to create.
|
||||
*/
|
||||
isa_bus = isa_bus_new(NULL, &lpc->isa_mem, &lpc->isa_io, &local_err);
|
||||
|
952
hw/ppc/spapr.c
952
hw/ppc/spapr.c
File diff suppressed because it is too large
Load Diff
@ -509,17 +509,14 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val,
|
||||
}
|
||||
}
|
||||
|
||||
static void cap_fwnmi_mce_apply(SpaprMachineState *spapr, uint8_t val,
|
||||
static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val,
|
||||
Error **errp)
|
||||
{
|
||||
if (!val) {
|
||||
return; /* Disabled by default */
|
||||
}
|
||||
|
||||
if (tcg_enabled()) {
|
||||
warn_report("Firmware Assisted Non-Maskable Interrupts(FWNMI) not "
|
||||
"supported in TCG");
|
||||
} else if (kvm_enabled()) {
|
||||
if (kvm_enabled()) {
|
||||
if (kvmppc_set_fwnmi() < 0) {
|
||||
error_setg(errp, "Firmware Assisted Non-Maskable Interrupts(FWNMI) "
|
||||
"not supported by KVM");
|
||||
@ -626,14 +623,14 @@ SpaprCapabilityInfo capability_table[SPAPR_CAP_NUM] = {
|
||||
.type = "bool",
|
||||
.apply = cap_ccf_assist_apply,
|
||||
},
|
||||
[SPAPR_CAP_FWNMI_MCE] = {
|
||||
.name = "fwnmi-mce",
|
||||
.description = "Handle fwnmi machine check exceptions",
|
||||
.index = SPAPR_CAP_FWNMI_MCE,
|
||||
[SPAPR_CAP_FWNMI] = {
|
||||
.name = "fwnmi",
|
||||
.description = "Implements PAPR FWNMI option",
|
||||
.index = SPAPR_CAP_FWNMI,
|
||||
.get = spapr_cap_get_bool,
|
||||
.set = spapr_cap_set_bool,
|
||||
.type = "bool",
|
||||
.apply = cap_fwnmi_mce_apply,
|
||||
.apply = cap_fwnmi_apply,
|
||||
},
|
||||
};
|
||||
|
||||
@ -774,7 +771,7 @@ SPAPR_CAP_MIG_STATE(hpt_maxpagesize, SPAPR_CAP_HPT_MAXPAGESIZE);
|
||||
SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV);
|
||||
SPAPR_CAP_MIG_STATE(large_decr, SPAPR_CAP_LARGE_DECREMENTER);
|
||||
SPAPR_CAP_MIG_STATE(ccf_assist, SPAPR_CAP_CCF_ASSIST);
|
||||
SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI_MCE);
|
||||
SPAPR_CAP_MIG_STATE(fwnmi, SPAPR_CAP_FWNMI);
|
||||
|
||||
void spapr_caps_init(SpaprMachineState *spapr)
|
||||
{
|
||||
|
@ -50,22 +50,14 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
|
||||
* the settings below ensure proper operations with TCG in absence of
|
||||
* a real hypervisor.
|
||||
*
|
||||
* Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
|
||||
* real mode accesses, which thankfully defaults to 0 and isn't
|
||||
* accessible in guest mode.
|
||||
*
|
||||
* Disable Power-saving mode Exit Cause exceptions for the CPU, so
|
||||
* we don't get spurious wakups before an RTAS start-cpu call.
|
||||
* For the same reason, set PSSCR_EC.
|
||||
*/
|
||||
lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
|
||||
lpcr &= ~(LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
|
||||
lpcr |= LPCR_LPES0 | LPCR_LPES1;
|
||||
env->spr[SPR_PSSCR] |= PSSCR_EC;
|
||||
|
||||
/* Set RMLS to the max (ie, 16G) */
|
||||
lpcr &= ~LPCR_RMLS;
|
||||
lpcr |= 1ull << LPCR_RMLS_SHIFT;
|
||||
|
||||
ppc_store_lpcr(cpu, lpcr);
|
||||
|
||||
/* Set a full AMOR so guest can use the AMR as it sees fit */
|
||||
@ -84,13 +76,17 @@ static void spapr_reset_vcpu(PowerPCCPU *cpu)
|
||||
spapr_irq_cpu_intc_reset(spapr, cpu);
|
||||
}
|
||||
|
||||
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
|
||||
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
|
||||
target_ulong r1, target_ulong r3,
|
||||
target_ulong r4)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->nip = nip;
|
||||
env->gpr[1] = r1;
|
||||
env->gpr[3] = r3;
|
||||
env->gpr[4] = r4;
|
||||
kvmppc_set_reg_ppc_online(cpu, 1);
|
||||
CPU(cpu)->halted = 0;
|
||||
/* Enable Power-saving mode Exit Cause exceptions */
|
||||
|
@ -786,28 +786,12 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
|
||||
{
|
||||
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
|
||||
CPUState *cs = CPU(cpu);
|
||||
uint64_t rtas_addr;
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
target_ulong msr = 0;
|
||||
uint64_t rtas_addr;
|
||||
struct rtas_error_log log;
|
||||
struct mc_extended_log *ext_elog;
|
||||
uint32_t summary;
|
||||
|
||||
/*
|
||||
* Properly set bits in MSR before we invoke the handler.
|
||||
* SRR0/1, DAR and DSISR are properly set by KVM
|
||||
*/
|
||||
if (!(*pcc->interrupts_big_endian)(cpu)) {
|
||||
msr |= (1ULL << MSR_LE);
|
||||
}
|
||||
|
||||
if (env->msr & (1ULL << MSR_SF)) {
|
||||
msr |= (1ULL << MSR_SF);
|
||||
}
|
||||
|
||||
msr |= (1ULL << MSR_ME);
|
||||
|
||||
ext_elog = g_malloc0(sizeof(*ext_elog));
|
||||
summary = spapr_mce_get_elog_type(cpu, recovered, ext_elog);
|
||||
|
||||
@ -823,8 +807,7 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
|
||||
/* get rtas addr from fdt */
|
||||
rtas_addr = spapr_get_rtas_addr();
|
||||
if (!rtas_addr) {
|
||||
/* Unable to fetch rtas_addr. Hence reset the guest */
|
||||
ppc_cpu_do_system_reset(cs);
|
||||
qemu_system_guest_panicked(NULL);
|
||||
g_free(ext_elog);
|
||||
return;
|
||||
}
|
||||
@ -836,12 +819,11 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered)
|
||||
cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET +
|
||||
sizeof(env->gpr[3]) + sizeof(log), ext_elog,
|
||||
sizeof(*ext_elog));
|
||||
g_free(ext_elog);
|
||||
|
||||
env->gpr[3] = rtas_addr + RTAS_ERROR_LOG_OFFSET;
|
||||
env->msr = msr;
|
||||
env->nip = spapr->guest_machine_check_addr;
|
||||
|
||||
g_free(ext_elog);
|
||||
ppc_cpu_do_fwnmi_machine_check(cs, spapr->fwnmi_machine_check_addr);
|
||||
}
|
||||
|
||||
void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
|
||||
@ -851,7 +833,7 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (spapr->guest_machine_check_addr == -1) {
|
||||
if (spapr->fwnmi_machine_check_addr == -1) {
|
||||
/*
|
||||
* This implies that we have hit a machine check either when the
|
||||
* guest has not registered FWNMI (i.e., "ibm,nmi-register" not
|
||||
@ -863,19 +845,19 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
|
||||
return;
|
||||
}
|
||||
|
||||
while (spapr->mc_status != -1) {
|
||||
while (spapr->fwnmi_machine_check_interlock != -1) {
|
||||
/*
|
||||
* Check whether the same CPU got machine check error
|
||||
* while still handling the mc error (i.e., before
|
||||
* that CPU called "ibm,nmi-interlock")
|
||||
*/
|
||||
if (spapr->mc_status == cpu->vcpu_id) {
|
||||
if (spapr->fwnmi_machine_check_interlock == cpu->vcpu_id) {
|
||||
qemu_system_guest_panicked(NULL);
|
||||
return;
|
||||
}
|
||||
qemu_cond_wait_iothread(&spapr->mc_delivery_cond);
|
||||
qemu_cond_wait_iothread(&spapr->fwnmi_machine_check_interlock_cond);
|
||||
/* Meanwhile if the system is reset, then just return */
|
||||
if (spapr->guest_machine_check_addr == -1) {
|
||||
if (spapr->fwnmi_machine_check_addr == -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -891,7 +873,7 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered)
|
||||
warn_report("Received a fwnmi while migration was in progress");
|
||||
}
|
||||
|
||||
spapr->mc_status = cpu->vcpu_id;
|
||||
spapr->fwnmi_machine_check_interlock = cpu->vcpu_id;
|
||||
spapr_mce_dispatch_elog(cpu, recovered);
|
||||
}
|
||||
|
||||
@ -983,6 +965,19 @@ void spapr_clear_pending_events(SpaprMachineState *spapr)
|
||||
}
|
||||
}
|
||||
|
||||
void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr)
|
||||
{
|
||||
SpaprEventLogEntry *entry = NULL, *next_entry;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(entry, &spapr->pending_events, next, next_entry) {
|
||||
if (spapr_event_log_entry_type(entry) == RTAS_LOG_TYPE_HOTPLUG) {
|
||||
QTAILQ_REMOVE(&spapr->pending_events, entry, next);
|
||||
g_free(entry->extended_log);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spapr_events_init(SpaprMachineState *spapr)
|
||||
{
|
||||
int epow_irq = SPAPR_IRQ_EPOW;
|
||||
|
@ -1458,7 +1458,7 @@ static void spapr_check_setup_free_hpt(SpaprMachineState *spapr,
|
||||
spapr_free_hpt(spapr);
|
||||
} else if (!(patbe_new & PATE1_GR)) {
|
||||
/* RADIX->HASH || NOTHING->HASH : Allocate HPT */
|
||||
spapr_setup_hpt_and_vrma(spapr);
|
||||
spapr_setup_hpt(spapr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1640,7 +1640,7 @@ static uint32_t cas_check_pvr(SpaprMachineState *spapr, PowerPCCPU *cpu,
|
||||
return best_compat;
|
||||
}
|
||||
|
||||
static bool spapr_transient_dev_before_cas(void)
|
||||
static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
|
||||
{
|
||||
Object *drc_container;
|
||||
ObjectProperty *prop;
|
||||
@ -1658,10 +1658,11 @@ static bool spapr_transient_dev_before_cas(void)
|
||||
prop->name, NULL));
|
||||
|
||||
if (spapr_drc_transient(drc)) {
|
||||
return true;
|
||||
spapr_drc_reset(drc);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
spapr_clear_pending_hotplug_events(spapr);
|
||||
}
|
||||
|
||||
static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
||||
@ -1834,9 +1835,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
||||
|
||||
spapr_irq_update_active_intc(spapr);
|
||||
|
||||
if (spapr_transient_dev_before_cas()) {
|
||||
spapr->cas_reboot = true;
|
||||
}
|
||||
spapr_handle_transient_dev_before_cas(spapr);
|
||||
|
||||
if (!spapr->cas_reboot) {
|
||||
void *fdt;
|
||||
@ -1846,7 +1845,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
|
||||
* (because the guest isn't going to use radix) then set it up here. */
|
||||
if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
|
||||
/* legacy hash or new hash: */
|
||||
spapr_setup_hpt_and_vrma(spapr);
|
||||
spapr_setup_hpt(spapr);
|
||||
}
|
||||
|
||||
if (fdt_bufsize < sizeof(hdr)) {
|
||||
|
@ -35,6 +35,7 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size,
|
||||
{
|
||||
char *uuidstr = NULL;
|
||||
QemuUUID uuid;
|
||||
int ret;
|
||||
|
||||
if (size % SPAPR_MINIMUM_SCM_BLOCK_SIZE) {
|
||||
error_setg(errp, "NVDIMM memory size excluding the label area"
|
||||
@ -43,8 +44,10 @@ void spapr_nvdimm_validate_opts(NVDIMMDevice *nvdimm, uint64_t size,
|
||||
return;
|
||||
}
|
||||
|
||||
uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP, NULL);
|
||||
qemu_uuid_parse(uuidstr, &uuid);
|
||||
uuidstr = object_property_get_str(OBJECT(nvdimm), NVDIMM_UUID_PROP,
|
||||
&error_abort);
|
||||
ret = qemu_uuid_parse(uuidstr, &uuid);
|
||||
g_assert(!ret);
|
||||
g_free(uuidstr);
|
||||
|
||||
if (qemu_uuid_is_null(&uuid)) {
|
||||
|
@ -200,8 +200,8 @@ SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector)
|
||||
return ov;
|
||||
}
|
||||
|
||||
int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
|
||||
SpaprOptionVector *ov, const char *name)
|
||||
int spapr_dt_ovec(void *fdt, int fdt_offset,
|
||||
SpaprOptionVector *ov, const char *name)
|
||||
{
|
||||
uint8_t vec[OV_MAXBYTES + 1];
|
||||
uint16_t vec_len;
|
||||
|
@ -190,7 +190,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr,
|
||||
*/
|
||||
newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset;
|
||||
|
||||
spapr_cpu_set_entry_state(newcpu, start, r3);
|
||||
spapr_cpu_set_entry_state(newcpu, start, 0, r3, 0);
|
||||
|
||||
qemu_cpu_kick(CPU(newcpu));
|
||||
|
||||
@ -414,8 +414,9 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
hwaddr rtas_addr;
|
||||
target_ulong sreset_addr, mce_addr;
|
||||
|
||||
if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
|
||||
if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
|
||||
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
@ -426,7 +427,19 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu,
|
||||
return;
|
||||
}
|
||||
|
||||
spapr->guest_machine_check_addr = rtas_ld(args, 1);
|
||||
sreset_addr = rtas_ld(args, 0);
|
||||
mce_addr = rtas_ld(args, 1);
|
||||
|
||||
/* PAPR requires these are in the first 32M of memory and within RMA */
|
||||
if (sreset_addr >= 32 * MiB || sreset_addr >= spapr->rma_size ||
|
||||
mce_addr >= 32 * MiB || mce_addr >= spapr->rma_size) {
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
spapr->fwnmi_system_reset_addr = sreset_addr;
|
||||
spapr->fwnmi_machine_check_addr = mce_addr;
|
||||
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
}
|
||||
|
||||
@ -436,29 +449,39 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu,
|
||||
target_ulong args,
|
||||
uint32_t nret, target_ulong rets)
|
||||
{
|
||||
if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI_MCE) == SPAPR_CAP_OFF) {
|
||||
if (spapr_get_cap(spapr, SPAPR_CAP_FWNMI) == SPAPR_CAP_OFF) {
|
||||
rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spapr->guest_machine_check_addr == -1) {
|
||||
if (spapr->fwnmi_machine_check_addr == -1) {
|
||||
/* NMI register not called */
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spapr->mc_status != cpu->vcpu_id) {
|
||||
/* The vCPU that hit the NMI should invoke "ibm,nmi-interlock" */
|
||||
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
|
||||
if (spapr->fwnmi_machine_check_interlock != cpu->vcpu_id) {
|
||||
/*
|
||||
* The vCPU that hit the NMI should invoke "ibm,nmi-interlock"
|
||||
* This should be PARAM_ERROR, but Linux calls "ibm,nmi-interlock"
|
||||
* for system reset interrupts, despite them not being interlocked.
|
||||
* PowerVM silently ignores this and returns success here. Returning
|
||||
* failure causes Linux to print the error "FWNMI: nmi-interlock
|
||||
* failed: -3", although no other apparent ill effects, this is a
|
||||
* regression for the user when enabling FWNMI. So for now, match
|
||||
* PowerVM. When most Linux clients are fixed, this could be
|
||||
* changed.
|
||||
*/
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* vCPU issuing "ibm,nmi-interlock" is done with NMI handling,
|
||||
* hence unset mc_status.
|
||||
* hence unset fwnmi_machine_check_interlock.
|
||||
*/
|
||||
spapr->mc_status = -1;
|
||||
qemu_cond_signal(&spapr->mc_delivery_cond);
|
||||
spapr->fwnmi_machine_check_interlock = -1;
|
||||
qemu_cond_signal(&spapr->fwnmi_machine_check_interlock_cond);
|
||||
rtas_st(rets, 0, RTAS_OUT_SUCCESS);
|
||||
migrate_del_blocker(spapr->fwnmi_migration_blocker);
|
||||
}
|
||||
|
@ -55,6 +55,8 @@
|
||||
#define VSCSI_MAX_SECTORS 4096
|
||||
#define VSCSI_REQ_LIMIT 24
|
||||
|
||||
/* Maximum size of a IU payload */
|
||||
#define SRP_MAX_IU_DATA_LEN (SRP_MAX_IU_LEN - sizeof(union srp_iu))
|
||||
#define SRP_RSP_SENSE_DATA_LEN 18
|
||||
|
||||
#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
|
||||
@ -66,7 +68,7 @@ typedef union vscsi_crq {
|
||||
|
||||
typedef struct vscsi_req {
|
||||
vscsi_crq crq;
|
||||
union viosrp_iu iu;
|
||||
uint8_t viosrp_iu_buf[SRP_MAX_IU_LEN];
|
||||
|
||||
/* SCSI request tracking */
|
||||
SCSIRequest *sreq;
|
||||
@ -97,6 +99,11 @@ typedef struct {
|
||||
vscsi_req reqs[VSCSI_REQ_LIMIT];
|
||||
} VSCSIState;
|
||||
|
||||
static union viosrp_iu *req_iu(vscsi_req *req)
|
||||
{
|
||||
return (union viosrp_iu *)req->viosrp_iu_buf;
|
||||
}
|
||||
|
||||
static struct vscsi_req *vscsi_get_req(VSCSIState *s)
|
||||
{
|
||||
vscsi_req *req;
|
||||
@ -121,7 +128,7 @@ static struct vscsi_req *vscsi_find_req(VSCSIState *s, uint64_t srp_tag)
|
||||
|
||||
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
|
||||
req = &s->reqs[i];
|
||||
if (req->iu.srp.cmd.tag == srp_tag) {
|
||||
if (req_iu(req)->srp.cmd.tag == srp_tag) {
|
||||
return req;
|
||||
}
|
||||
}
|
||||
@ -176,9 +183,11 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
|
||||
{
|
||||
long rc, rc1;
|
||||
|
||||
assert(length <= SRP_MAX_IU_LEN);
|
||||
|
||||
/* First copy the SRP */
|
||||
rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
|
||||
&req->iu, length);
|
||||
&req->viosrp_iu_buf, length);
|
||||
if (rc) {
|
||||
fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
|
||||
}
|
||||
@ -188,7 +197,7 @@ static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
|
||||
req->crq.s.reserved = 0x00;
|
||||
req->crq.s.timeout = cpu_to_be16(0x0000);
|
||||
req->crq.s.IU_length = cpu_to_be16(length);
|
||||
req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
|
||||
req->crq.s.IU_data_ptr = req_iu(req)->srp.rsp.tag; /* right byte order */
|
||||
|
||||
if (rc == 0) {
|
||||
req->crq.s.status = VIOSRP_OK;
|
||||
@ -224,7 +233,7 @@ static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
|
||||
static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
|
||||
uint8_t status, int32_t res_in, int32_t res_out)
|
||||
{
|
||||
union viosrp_iu *iu = &req->iu;
|
||||
union viosrp_iu *iu = req_iu(req);
|
||||
uint64_t tag = iu->srp.rsp.tag;
|
||||
int total_len = sizeof(iu->srp.rsp);
|
||||
uint8_t sol_not = iu->srp.cmd.sol_not;
|
||||
@ -261,10 +270,12 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
|
||||
if (status) {
|
||||
iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2;
|
||||
if (req->senselen) {
|
||||
req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
|
||||
req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
|
||||
memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
|
||||
total_len += req->senselen;
|
||||
int sense_data_len = MIN(req->senselen, SRP_MAX_IU_DATA_LEN);
|
||||
|
||||
iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
|
||||
iu->srp.rsp.sense_data_len = cpu_to_be32(sense_data_len);
|
||||
memcpy(iu->srp.rsp.data, req->sense, sense_data_len);
|
||||
total_len += sense_data_len;
|
||||
}
|
||||
} else {
|
||||
iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1;
|
||||
@ -285,7 +296,7 @@ static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req,
|
||||
unsigned n, unsigned buf_offset,
|
||||
struct srp_direct_buf *ret)
|
||||
{
|
||||
struct srp_cmd *cmd = &req->iu.srp.cmd;
|
||||
struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
|
||||
|
||||
switch (req->dma_fmt) {
|
||||
case SRP_NO_DATA_DESC: {
|
||||
@ -473,7 +484,7 @@ static int data_out_desc_size(struct srp_cmd *cmd)
|
||||
|
||||
static int vscsi_preprocess_desc(vscsi_req *req)
|
||||
{
|
||||
struct srp_cmd *cmd = &req->iu.srp.cmd;
|
||||
struct srp_cmd *cmd = &req_iu(req)->srp.cmd;
|
||||
|
||||
req->cdb_offset = cmd->add_cdb_len & ~3;
|
||||
|
||||
@ -597,7 +608,7 @@ static const VMStateDescription vmstate_spapr_vscsi_req = {
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BUFFER(crq.raw, vscsi_req),
|
||||
VMSTATE_BUFFER(iu.srp.reserved, vscsi_req),
|
||||
VMSTATE_BUFFER(viosrp_iu_buf, vscsi_req),
|
||||
VMSTATE_UINT32(qtag, vscsi_req),
|
||||
VMSTATE_BOOL(active, vscsi_req),
|
||||
VMSTATE_UINT32(data_len, vscsi_req),
|
||||
@ -655,7 +666,7 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq)
|
||||
|
||||
static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
union viosrp_iu *iu = &req->iu;
|
||||
union viosrp_iu *iu = req_iu(req);
|
||||
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
|
||||
uint64_t tag = iu->srp.rsp.tag;
|
||||
|
||||
@ -671,8 +682,8 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
|
||||
*/
|
||||
rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
|
||||
rsp->tag = tag;
|
||||
rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
|
||||
rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
|
||||
rsp->max_it_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
|
||||
rsp->max_ti_iu_len = cpu_to_be32(SRP_MAX_IU_LEN);
|
||||
/* direct and indirect */
|
||||
rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
|
||||
|
||||
@ -681,7 +692,7 @@ static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
uint8_t *cdb = req->iu.srp.cmd.cdb;
|
||||
uint8_t *cdb = req_iu(req)->srp.cmd.cdb;
|
||||
uint8_t resp_data[36];
|
||||
int rc, len, alen;
|
||||
|
||||
@ -770,7 +781,7 @@ static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
union srp_iu *srp = &req->iu.srp;
|
||||
union srp_iu *srp = &req_iu(req)->srp;
|
||||
SCSIDevice *sdev;
|
||||
int n, lun;
|
||||
|
||||
@ -821,17 +832,16 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
union viosrp_iu *iu = &req->iu;
|
||||
union viosrp_iu *iu = req_iu(req);
|
||||
vscsi_req *tmpreq;
|
||||
int i, lun = 0, resp = SRP_TSK_MGMT_COMPLETE;
|
||||
SCSIDevice *d;
|
||||
uint64_t tag = iu->srp.rsp.tag;
|
||||
uint8_t sol_not = iu->srp.cmd.sol_not;
|
||||
|
||||
fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
|
||||
iu->srp.tsk_mgmt.tsk_mgmt_func);
|
||||
|
||||
d = vscsi_device_find(&s->bus, be64_to_cpu(req->iu.srp.tsk_mgmt.lun), &lun);
|
||||
trace_spapr_vscsi_process_tsk_mgmt(iu->srp.tsk_mgmt.tsk_mgmt_func);
|
||||
d = vscsi_device_find(&s->bus,
|
||||
be64_to_cpu(req_iu(req)->srp.tsk_mgmt.lun), &lun);
|
||||
if (!d) {
|
||||
resp = SRP_TSK_MGMT_FIELDS_INVALID;
|
||||
} else {
|
||||
@ -842,7 +852,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
break;
|
||||
}
|
||||
|
||||
tmpreq = vscsi_find_req(s, req->iu.srp.tsk_mgmt.task_tag);
|
||||
tmpreq = vscsi_find_req(s, req_iu(req)->srp.tsk_mgmt.task_tag);
|
||||
if (tmpreq && tmpreq->sreq) {
|
||||
assert(tmpreq->sreq->hba_private);
|
||||
scsi_req_cancel(tmpreq->sreq);
|
||||
@ -867,7 +877,8 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
|
||||
tmpreq = &s->reqs[i];
|
||||
if (tmpreq->iu.srp.cmd.lun != req->iu.srp.tsk_mgmt.lun) {
|
||||
if (req_iu(tmpreq)->srp.cmd.lun
|
||||
!= req_iu(req)->srp.tsk_mgmt.lun) {
|
||||
continue;
|
||||
}
|
||||
if (!tmpreq->active || !tmpreq->sreq) {
|
||||
@ -889,6 +900,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
}
|
||||
|
||||
/* Compose the response here as */
|
||||
QEMU_BUILD_BUG_ON(SRP_MAX_IU_DATA_LEN < 4);
|
||||
memset(iu, 0, sizeof(struct srp_rsp) + 4);
|
||||
iu->srp.rsp.opcode = SRP_RSP;
|
||||
iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
|
||||
@ -911,7 +923,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
union srp_iu *srp = &req->iu.srp;
|
||||
union srp_iu *srp = &req_iu(req)->srp;
|
||||
int done = 1;
|
||||
uint8_t opcode = srp->rsp.opcode;
|
||||
|
||||
@ -948,7 +960,7 @@ static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
|
||||
struct mad_adapter_info_data info;
|
||||
int rc;
|
||||
|
||||
sinfo = &req->iu.mad.adapter_info;
|
||||
sinfo = &req_iu(req)->mad.adapter_info;
|
||||
|
||||
#if 0 /* What for ? */
|
||||
rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
|
||||
@ -984,7 +996,7 @@ static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
|
||||
uint64_t buffer;
|
||||
int rc;
|
||||
|
||||
vcap = &req->iu.mad.capabilities;
|
||||
vcap = &req_iu(req)->mad.capabilities;
|
||||
req_len = len = be16_to_cpu(vcap->common.length);
|
||||
buffer = be64_to_cpu(vcap->buffer);
|
||||
if (len > sizeof(cap)) {
|
||||
@ -1029,7 +1041,7 @@ static int vscsi_send_capabilities(VSCSIState *s, vscsi_req *req)
|
||||
|
||||
static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
|
||||
{
|
||||
union mad_iu *mad = &req->iu.mad;
|
||||
union mad_iu *mad = &req_iu(req)->mad;
|
||||
bool request_handled = false;
|
||||
uint64_t retlen = 0;
|
||||
|
||||
@ -1088,7 +1100,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
|
||||
* in our 256 bytes IUs. If not we'll have to increase the size
|
||||
* of the structure.
|
||||
*/
|
||||
if (crq->s.IU_length > sizeof(union viosrp_iu)) {
|
||||
if (crq->s.IU_length > SRP_MAX_IU_LEN) {
|
||||
fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
|
||||
crq->s.IU_length);
|
||||
vscsi_put_req(req);
|
||||
@ -1096,7 +1108,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
|
||||
}
|
||||
|
||||
/* XXX Handle failure differently ? */
|
||||
if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
|
||||
if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->viosrp_iu_buf,
|
||||
crq->s.IU_length)) {
|
||||
fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
|
||||
vscsi_put_req(req);
|
||||
|
@ -227,6 +227,7 @@ spapr_vscsi_command_complete_status(uint32_t status) "Command complete err=%"PRI
|
||||
spapr_vscsi_save_request(uint32_t qtag, unsigned desc, unsigned offset) "saving tag=%"PRIu32", current desc#%u, offset=0x%x"
|
||||
spapr_vscsi_load_request(uint32_t qtag, unsigned desc, unsigned offset) "restoring tag=%"PRIu32", current desc#%u, offset=0x%x"
|
||||
spapr_vscsi_process_login(void) "Got login, sending response !"
|
||||
spapr_vscsi_process_tsk_mgmt(uint8_t func) "tsk_mgmt_func 0x%02x"
|
||||
spapr_vscsi_queue_cmd_no_drive(uint64_t lun) "Command for lun 0x%08" PRIx64 " with no drive"
|
||||
spapr_vscsi_queue_cmd(uint32_t qtag, unsigned cdb, const char *cmd, int lun, int ret) "Queued command tag 0x%"PRIx32" CMD 0x%x=%s LUN %d ret: %d"
|
||||
spapr_vscsi_do_crq(unsigned c0, unsigned c1) "crq: %02x %02x ..."
|
||||
|
@ -34,6 +34,8 @@
|
||||
#ifndef PPC_VIOSRP_H
|
||||
#define PPC_VIOSRP_H
|
||||
|
||||
#include "hw/scsi/srp.h"
|
||||
|
||||
#define SRP_VERSION "16.a"
|
||||
#define SRP_MAX_IU_LEN 256
|
||||
#define SRP_MAX_LOC_LEN 32
|
||||
@ -47,7 +49,6 @@ union srp_iu {
|
||||
struct srp_tsk_mgmt tsk_mgmt;
|
||||
struct srp_cmd cmd;
|
||||
struct srp_rsp rsp;
|
||||
uint8_t reserved[SRP_MAX_IU_LEN];
|
||||
};
|
||||
|
||||
enum viosrp_crq_formats {
|
||||
|
@ -79,10 +79,10 @@ typedef enum {
|
||||
#define SPAPR_CAP_LARGE_DECREMENTER 0x08
|
||||
/* Count Cache Flush Assist HW Instruction */
|
||||
#define SPAPR_CAP_CCF_ASSIST 0x09
|
||||
/* FWNMI machine check handling */
|
||||
#define SPAPR_CAP_FWNMI_MCE 0x0A
|
||||
/* Implements PAPR FWNMI option */
|
||||
#define SPAPR_CAP_FWNMI 0x0A
|
||||
/* Num Caps */
|
||||
#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI_MCE + 1)
|
||||
#define SPAPR_CAP_NUM (SPAPR_CAP_FWNMI + 1)
|
||||
|
||||
/*
|
||||
* Capability Values
|
||||
@ -126,6 +126,7 @@ struct SpaprMachineClass {
|
||||
bool pre_4_1_migration; /* don't migrate hpt-max-page-size */
|
||||
bool linux_pci_probe;
|
||||
bool smp_threads_vsmt; /* set VSMT to smp_threads by default */
|
||||
hwaddr rma_limit; /* clamp the RMA to this size */
|
||||
|
||||
void (*phb_placement)(SpaprMachineState *spapr, uint32_t index,
|
||||
uint64_t *buid, hwaddr *pio,
|
||||
@ -156,7 +157,6 @@ struct SpaprMachineState {
|
||||
SpaprPendingHpt *pending_hpt; /* in-progress resize */
|
||||
|
||||
hwaddr rma_size;
|
||||
int vrma_adjust;
|
||||
uint32_t fdt_size;
|
||||
uint32_t fdt_initial_size;
|
||||
void *fdt_blob;
|
||||
@ -192,14 +192,22 @@ struct SpaprMachineState {
|
||||
* occurs during the unplug process. */
|
||||
QTAILQ_HEAD(, SpaprDimmState) pending_dimm_unplugs;
|
||||
|
||||
/* State related to "ibm,nmi-register" and "ibm,nmi-interlock" calls */
|
||||
target_ulong guest_machine_check_addr;
|
||||
/*
|
||||
* mc_status is set to -1 if mc is not in progress, else is set to the CPU
|
||||
* handling the mc.
|
||||
/* State related to FWNMI option */
|
||||
|
||||
/* System Reset and Machine Check Notification Routine addresses
|
||||
* registered by "ibm,nmi-register" RTAS call.
|
||||
*/
|
||||
int mc_status;
|
||||
QemuCond mc_delivery_cond;
|
||||
target_ulong fwnmi_system_reset_addr;
|
||||
target_ulong fwnmi_machine_check_addr;
|
||||
|
||||
/* Machine Check FWNMI synchronization, fwnmi_machine_check_interlock is
|
||||
* set to -1 if a FWNMI machine check is not in progress, else is set to
|
||||
* the CPU that was delivered the machine check, and is set back to -1
|
||||
* when that CPU makes an "ibm,nmi-interlock" RTAS call. The cond is used
|
||||
* to synchronize other CPUs.
|
||||
*/
|
||||
int fwnmi_machine_check_interlock;
|
||||
QemuCond fwnmi_machine_check_interlock_cond;
|
||||
|
||||
/*< public >*/
|
||||
char *kvm_type;
|
||||
@ -736,6 +744,7 @@ void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr);
|
||||
#define SPAPR_IS_PCI_LIOBN(liobn) (!!((liobn) & 0x80000000))
|
||||
#define SPAPR_PCI_DMA_WINDOW_NUM(liobn) ((liobn) & 0xff)
|
||||
|
||||
#define RTAS_SIZE 2048
|
||||
#define RTAS_ERROR_LOG_MAX 2048
|
||||
|
||||
/* Offset from rtas-base where error log is placed */
|
||||
@ -795,7 +804,7 @@ void *spapr_build_fdt(SpaprMachineState *spapr, bool reset, size_t space);
|
||||
void spapr_events_init(SpaprMachineState *sm);
|
||||
void spapr_dt_events(SpaprMachineState *sm, void *fdt);
|
||||
void close_htab_fd(SpaprMachineState *spapr);
|
||||
void spapr_setup_hpt_and_vrma(SpaprMachineState *spapr);
|
||||
void spapr_setup_hpt(SpaprMachineState *spapr);
|
||||
void spapr_free_hpt(SpaprMachineState *spapr);
|
||||
SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn);
|
||||
void spapr_tce_table_enable(SpaprTceTable *tcet,
|
||||
@ -824,6 +833,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
|
||||
void spapr_reallocate_hpt(SpaprMachineState *spapr, int shift,
|
||||
Error **errp);
|
||||
void spapr_clear_pending_events(SpaprMachineState *spapr);
|
||||
void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr);
|
||||
int spapr_max_server_number(SpaprMachineState *spapr);
|
||||
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
|
||||
uint64_t pte0, uint64_t pte1);
|
||||
|
@ -40,7 +40,9 @@ typedef struct SpaprCpuCoreClass {
|
||||
} SpaprCpuCoreClass;
|
||||
|
||||
const char *spapr_get_cpu_core_type(const char *cpu_type);
|
||||
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3);
|
||||
void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
|
||||
target_ulong r1, target_ulong r3,
|
||||
target_ulong r4);
|
||||
|
||||
typedef struct SpaprCpuState {
|
||||
uint64_t vpa_addr;
|
||||
|
@ -72,8 +72,8 @@ void spapr_ovec_set(SpaprOptionVector *ov, long bitnr);
|
||||
void spapr_ovec_clear(SpaprOptionVector *ov, long bitnr);
|
||||
bool spapr_ovec_test(SpaprOptionVector *ov, long bitnr);
|
||||
SpaprOptionVector *spapr_ovec_parse_vector(target_ulong table_addr, int vector);
|
||||
int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
|
||||
SpaprOptionVector *ov, const char *name);
|
||||
int spapr_dt_ovec(void *fdt, int fdt_offset,
|
||||
SpaprOptionVector *ov, const char *name);
|
||||
|
||||
/* migration */
|
||||
extern const VMStateDescription vmstate_spapr_ovec;
|
||||
|
@ -14,7 +14,7 @@
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
https://github.com/aik/SLOF, and the image currently in qemu is
|
||||
built from git tag qemu-slof-20191217.
|
||||
built from git tag qemu-slof-20200317.
|
||||
|
||||
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
|
||||
legacy x86 software to communicate with an attached serial console as
|
||||
|
BIN
pc-bios/slof.bin
BIN
pc-bios/slof.bin
Binary file not shown.
@ -1 +1 @@
|
||||
Subproject commit 9546892a80d5a4c73deea6719de46372f007f4a6
|
||||
Subproject commit ab6984f5a6d054e1f634dda855b32e5357111974
|
@ -177,6 +177,7 @@ typedef struct PowerPCCPUClass {
|
||||
uint64_t insns_flags;
|
||||
uint64_t insns_flags2;
|
||||
uint64_t msr_mask;
|
||||
uint64_t lpcr_mask; /* Available bits in the LPCR */
|
||||
uint64_t lpcr_pm; /* Power-saving mode Exit Cause Enable bits */
|
||||
powerpc_mmu_t mmu_model;
|
||||
powerpc_excp_t excp_model;
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "cpu-qom.h"
|
||||
|
||||
/* #define PPC_EMULATE_32BITS_HYPV */
|
||||
|
||||
#define TCG_GUEST_DEFAULT_MO 0
|
||||
|
||||
#define TARGET_PAGE_BITS_64K 16
|
||||
@ -300,13 +298,12 @@ typedef struct ppc_v3_pate_t {
|
||||
#define MSR_SF 63 /* Sixty-four-bit mode hflags */
|
||||
#define MSR_TAG 62 /* Tag-active mode (POWERx ?) */
|
||||
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
|
||||
#define MSR_SHV 60 /* hypervisor state hflags */
|
||||
#define MSR_HV 60 /* hypervisor state hflags */
|
||||
#define MSR_TS0 34 /* Transactional state, 2 bits (Book3s) */
|
||||
#define MSR_TS1 33
|
||||
#define MSR_TM 32 /* Transactional Memory Available (Book3s) */
|
||||
#define MSR_CM 31 /* Computation mode for BookE hflags */
|
||||
#define MSR_ICM 30 /* Interrupt computation mode for BookE */
|
||||
#define MSR_THV 29 /* hypervisor state for 32 bits PowerPC hflags */
|
||||
#define MSR_GS 28 /* guest state for BookE */
|
||||
#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
|
||||
#define MSR_VR 25 /* altivec available x hflags */
|
||||
@ -401,10 +398,13 @@ typedef struct ppc_v3_pate_t {
|
||||
|
||||
#define msr_sf ((env->msr >> MSR_SF) & 1)
|
||||
#define msr_isf ((env->msr >> MSR_ISF) & 1)
|
||||
#define msr_shv ((env->msr >> MSR_SHV) & 1)
|
||||
#if defined(TARGET_PPC64)
|
||||
#define msr_hv ((env->msr >> MSR_HV) & 1)
|
||||
#else
|
||||
#define msr_hv (0)
|
||||
#endif
|
||||
#define msr_cm ((env->msr >> MSR_CM) & 1)
|
||||
#define msr_icm ((env->msr >> MSR_ICM) & 1)
|
||||
#define msr_thv ((env->msr >> MSR_THV) & 1)
|
||||
#define msr_gs ((env->msr >> MSR_GS) & 1)
|
||||
#define msr_ucle ((env->msr >> MSR_UCLE) & 1)
|
||||
#define msr_vr ((env->msr >> MSR_VR) & 1)
|
||||
@ -449,16 +449,9 @@ typedef struct ppc_v3_pate_t {
|
||||
|
||||
/* Hypervisor bit is more specific */
|
||||
#if defined(TARGET_PPC64)
|
||||
#define MSR_HVB (1ULL << MSR_SHV)
|
||||
#define msr_hv msr_shv
|
||||
#else
|
||||
#if defined(PPC_EMULATE_32BITS_HYPV)
|
||||
#define MSR_HVB (1ULL << MSR_THV)
|
||||
#define msr_hv msr_thv
|
||||
#define MSR_HVB (1ULL << MSR_HV)
|
||||
#else
|
||||
#define MSR_HVB (0ULL)
|
||||
#define msr_hv (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* DSISR */
|
||||
@ -1051,10 +1044,6 @@ struct CPUPPCState {
|
||||
uint32_t flags;
|
||||
uint64_t insns_flags;
|
||||
uint64_t insns_flags2;
|
||||
#if defined(TARGET_PPC64)
|
||||
ppc_slb_t vrma_slb;
|
||||
target_ulong rmls;
|
||||
#endif
|
||||
|
||||
int error_code;
|
||||
uint32_t pending_interrupts;
|
||||
@ -1231,7 +1220,8 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void ppc_cpu_do_system_reset(CPUState *cs);
|
||||
void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector);
|
||||
void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector);
|
||||
extern const VMStateDescription vmstate_ppc_cpu;
|
||||
#endif
|
||||
|
||||
|
@ -128,6 +128,37 @@ static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline void powerpc_set_excp_state(PowerPCCPU *cpu,
|
||||
target_ulong vector, target_ulong msr)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
/*
|
||||
* We don't use hreg_store_msr here as already have treated any
|
||||
* special case that could occur. Just store MSR and update hflags
|
||||
*
|
||||
* Note: We *MUST* not use hreg_store_msr() as-is anyway because it
|
||||
* will prevent setting of the HV bit which some exceptions might need
|
||||
* to do.
|
||||
*/
|
||||
env->msr = msr & env->msr_mask;
|
||||
hreg_compute_hflags(env);
|
||||
env->nip = vector;
|
||||
/* Reset exception state */
|
||||
cs->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
|
||||
/* Reset the reservation */
|
||||
env->reserve_addr = -1;
|
||||
|
||||
/*
|
||||
* Any interrupt is context synchronizing, check if TCG TLB needs
|
||||
* a delayed flush on ppc64
|
||||
*/
|
||||
check_tlb_flush(env, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this function should be greatly optimized when called
|
||||
* with a constant excp, from ppc_hw_interrupt
|
||||
@ -768,29 +799,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* We don't use hreg_store_msr here as already have treated any
|
||||
* special case that could occur. Just store MSR and update hflags
|
||||
*
|
||||
* Note: We *MUST* not use hreg_store_msr() as-is anyway because it
|
||||
* will prevent setting of the HV bit which some exceptions might need
|
||||
* to do.
|
||||
*/
|
||||
env->msr = new_msr & env->msr_mask;
|
||||
hreg_compute_hflags(env);
|
||||
env->nip = vector;
|
||||
/* Reset exception state */
|
||||
cs->exception_index = POWERPC_EXCP_NONE;
|
||||
env->error_code = 0;
|
||||
|
||||
/* Reset the reservation */
|
||||
env->reserve_addr = -1;
|
||||
|
||||
/*
|
||||
* Any interrupt is context synchronizing, check if TCG TLB needs
|
||||
* a delayed flush on ppc64
|
||||
*/
|
||||
check_tlb_flush(env, false);
|
||||
powerpc_set_excp_state(cpu, vector, new_msr);
|
||||
}
|
||||
|
||||
void ppc_cpu_do_interrupt(CPUState *cs)
|
||||
@ -951,12 +961,35 @@ static void ppc_hw_interrupt(CPUPPCState *env)
|
||||
}
|
||||
}
|
||||
|
||||
void ppc_cpu_do_system_reset(CPUState *cs)
|
||||
void ppc_cpu_do_system_reset(CPUState *cs, target_ulong vector)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
|
||||
if (vector != -1) {
|
||||
env->nip = vector;
|
||||
}
|
||||
}
|
||||
|
||||
void ppc_cpu_do_fwnmi_machine_check(CPUState *cs, target_ulong vector)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
target_ulong msr = 0;
|
||||
|
||||
/*
|
||||
* Set MSR and NIP for the handler, SRR0/1, DAR and DSISR have already
|
||||
* been set by KVM.
|
||||
*/
|
||||
msr = (1ULL << MSR_ME);
|
||||
msr |= env->msr & (1ULL << MSR_SF);
|
||||
if (!(*pcc->interrupts_big_endian)(cpu)) {
|
||||
msr |= (1ULL << MSR_LE);
|
||||
}
|
||||
|
||||
powerpc_set_excp_state(cpu, vector, msr);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
|
@ -2113,7 +2113,7 @@ void kvmppc_error_append_smt_possible_hint(Error *const *errp)
|
||||
|
||||
|
||||
#ifdef TARGET_PPC64
|
||||
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
|
||||
uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
|
||||
{
|
||||
struct kvm_ppc_smmu_info info;
|
||||
long rampagesize, best_page_shift;
|
||||
@ -2140,8 +2140,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
|
||||
}
|
||||
}
|
||||
|
||||
return MIN(current_size,
|
||||
1ULL << (best_page_shift + hash_shift - 7));
|
||||
return 1ULL << (best_page_shift + hash_shift - 7);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -47,7 +47,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
|
||||
int *pfd, bool need_vfio);
|
||||
int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
|
||||
int kvmppc_reset_htab(int shift_hint);
|
||||
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
|
||||
uint64_t kvmppc_vrma_limit(unsigned int hash_shift);
|
||||
bool kvmppc_has_cap_spapr_vfio(void);
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
bool kvmppc_has_cap_epr(void);
|
||||
@ -255,10 +255,9 @@ static inline int kvmppc_reset_htab(int shift_hint)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint64_t kvmppc_rma_size(uint64_t current_size,
|
||||
unsigned int hash_shift)
|
||||
static inline uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
|
||||
{
|
||||
return ram_size;
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static inline bool kvmppc_hpt_needs_host_contiguous_pages(void)
|
||||
|
@ -18,6 +18,7 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
@ -668,6 +669,21 @@ unsigned ppc_hash64_hpte_page_shift_noslb(PowerPCCPU *cpu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ppc_hash64_use_vrma(CPUPPCState *env)
|
||||
{
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_3_00:
|
||||
/*
|
||||
* ISAv3.0 (POWER9) always uses VRMA, the VPM0 field and RMOR
|
||||
* register no longer exist
|
||||
*/
|
||||
return true;
|
||||
|
||||
default:
|
||||
return !!(env->spr[SPR_LPCR] & LPCR_VPM0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
|
||||
{
|
||||
CPUPPCState *env = &POWERPC_CPU(cs)->env;
|
||||
@ -676,15 +692,7 @@ static void ppc_hash64_set_isi(CPUState *cs, uint64_t error_code)
|
||||
if (msr_ir) {
|
||||
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
|
||||
} else {
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_3_00:
|
||||
/* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
|
||||
vpm = true;
|
||||
break;
|
||||
default:
|
||||
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
|
||||
break;
|
||||
}
|
||||
vpm = ppc_hash64_use_vrma(env);
|
||||
}
|
||||
if (vpm && !msr_hv) {
|
||||
cs->exception_index = POWERPC_EXCP_HISI;
|
||||
@ -702,15 +710,7 @@ static void ppc_hash64_set_dsi(CPUState *cs, uint64_t dar, uint64_t dsisr)
|
||||
if (msr_dr) {
|
||||
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM1);
|
||||
} else {
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_3_00:
|
||||
/* Field deprecated in ISAv3.00 - interrupts always go to hyperv */
|
||||
vpm = true;
|
||||
break;
|
||||
default:
|
||||
vpm = !!(env->spr[SPR_LPCR] & LPCR_VPM0);
|
||||
break;
|
||||
}
|
||||
vpm = ppc_hash64_use_vrma(env);
|
||||
}
|
||||
if (vpm && !msr_hv) {
|
||||
cs->exception_index = POWERPC_EXCP_HDSI;
|
||||
@ -758,11 +758,67 @@ static void ppc_hash64_set_c(PowerPCCPU *cpu, hwaddr ptex, uint64_t pte1)
|
||||
stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
|
||||
}
|
||||
|
||||
static target_ulong rmls_limit(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
/*
|
||||
* In theory the meanings of RMLS values are implementation
|
||||
* dependent. In practice, this seems to have been the set from
|
||||
* POWER4+..POWER8, and RMLS is no longer supported in POWER9.
|
||||
*
|
||||
* Unsupported values mean the OS has shot itself in the
|
||||
* foot. Return a 0-sized RMA in this case, which we expect
|
||||
* to trigger an immediate DSI or ISI
|
||||
*/
|
||||
static const target_ulong rma_sizes[16] = {
|
||||
[0] = 256 * GiB,
|
||||
[1] = 16 * GiB,
|
||||
[2] = 1 * GiB,
|
||||
[3] = 64 * MiB,
|
||||
[4] = 256 * MiB,
|
||||
[7] = 128 * MiB,
|
||||
[8] = 32 * MiB,
|
||||
};
|
||||
target_ulong rmls = (env->spr[SPR_LPCR] & LPCR_RMLS) >> LPCR_RMLS_SHIFT;
|
||||
|
||||
return rma_sizes[rmls];
|
||||
}
|
||||
|
||||
static int build_vrma_slbe(PowerPCCPU *cpu, ppc_slb_t *slb)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong lpcr = env->spr[SPR_LPCR];
|
||||
uint32_t vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
|
||||
target_ulong vsid = SLB_VSID_VRMA | ((vrmasd << 4) & SLB_VSID_LLP_MASK);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
|
||||
const PPCHash64SegmentPageSizes *sps = &cpu->hash64_opts->sps[i];
|
||||
|
||||
if (!sps->page_shift) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((vsid & SLB_VSID_LLP_MASK) == sps->slb_enc) {
|
||||
slb->esid = SLB_ESID_V;
|
||||
slb->vsid = vsid;
|
||||
slb->sps = sps;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error_report("Bad page size encoding in LPCR[VRMASD]; LPCR=0x"
|
||||
TARGET_FMT_lx"\n", lpcr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
||||
int rwx, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_slb_t vrma_slbe;
|
||||
ppc_slb_t *slb;
|
||||
unsigned apshift;
|
||||
hwaddr ptex;
|
||||
@ -789,27 +845,32 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
||||
*/
|
||||
raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
|
||||
|
||||
/* In HV mode, add HRMOR if top EA bit is clear */
|
||||
if (msr_hv || !env->has_hv_mode) {
|
||||
if (cpu->vhyp) {
|
||||
/*
|
||||
* In virtual hypervisor mode, there's nothing to do:
|
||||
* EA == GPA == qemu guest address
|
||||
*/
|
||||
} else if (msr_hv || !env->has_hv_mode) {
|
||||
/* In HV mode, add HRMOR if top EA bit is clear */
|
||||
if (!(eaddr >> 63)) {
|
||||
raddr |= env->spr[SPR_HRMOR];
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, check VPM for RMA vs VRMA */
|
||||
if (env->spr[SPR_LPCR] & LPCR_VPM0) {
|
||||
slb = &env->vrma_slb;
|
||||
if (slb->sps) {
|
||||
goto skip_slb_search;
|
||||
}
|
||||
/* Not much else to do here */
|
||||
} else if (ppc_hash64_use_vrma(env)) {
|
||||
/* Emulated VRMA mode */
|
||||
slb = &vrma_slbe;
|
||||
if (build_vrma_slbe(cpu, slb) != 0) {
|
||||
/* Invalid VRMA setup, machine check */
|
||||
cs->exception_index = POWERPC_EXCP_MCHECK;
|
||||
env->error_code = 0;
|
||||
return 1;
|
||||
} else if (raddr < env->rmls) {
|
||||
/* RMA. Check bounds in RMLS */
|
||||
raddr |= env->spr[SPR_RMOR];
|
||||
} else {
|
||||
/* The access failed, generate the approriate interrupt */
|
||||
}
|
||||
|
||||
goto skip_slb_search;
|
||||
} else {
|
||||
target_ulong limit = rmls_limit(cpu);
|
||||
|
||||
/* Emulated old-style RMO mode, bounds check against RMLS */
|
||||
if (raddr >= limit) {
|
||||
if (rwx == 2) {
|
||||
ppc_hash64_set_isi(cs, SRR1_PROTFAULT);
|
||||
} else {
|
||||
@ -821,6 +882,8 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr,
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
raddr |= env->spr[SPR_RMOR];
|
||||
}
|
||||
tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
|
||||
PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
|
||||
@ -943,6 +1006,7 @@ skip_slb_search:
|
||||
hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
ppc_slb_t vrma_slbe;
|
||||
ppc_slb_t *slb;
|
||||
hwaddr ptex, raddr;
|
||||
ppc_hash_pte64_t pte;
|
||||
@ -953,22 +1017,29 @@ hwaddr ppc_hash64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong addr)
|
||||
/* In real mode the top 4 effective address bits are ignored */
|
||||
raddr = addr & 0x0FFFFFFFFFFFFFFFULL;
|
||||
|
||||
/* In HV mode, add HRMOR if top EA bit is clear */
|
||||
if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
|
||||
if (cpu->vhyp) {
|
||||
/*
|
||||
* In virtual hypervisor mode, there's nothing to do:
|
||||
* EA == GPA == qemu guest address
|
||||
*/
|
||||
return raddr;
|
||||
} else if ((msr_hv || !env->has_hv_mode) && !(addr >> 63)) {
|
||||
/* In HV mode, add HRMOR if top EA bit is clear */
|
||||
return raddr | env->spr[SPR_HRMOR];
|
||||
}
|
||||
|
||||
/* Otherwise, check VPM for RMA vs VRMA */
|
||||
if (env->spr[SPR_LPCR] & LPCR_VPM0) {
|
||||
slb = &env->vrma_slb;
|
||||
if (!slb->sps) {
|
||||
} else if (ppc_hash64_use_vrma(env)) {
|
||||
/* Emulated VRMA mode */
|
||||
slb = &vrma_slbe;
|
||||
if (build_vrma_slbe(cpu, slb) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (raddr < env->rmls) {
|
||||
/* RMA. Check bounds in RMLS */
|
||||
return raddr | env->spr[SPR_RMOR];
|
||||
} else {
|
||||
return -1;
|
||||
target_ulong limit = rmls_limit(cpu);
|
||||
|
||||
/* Emulated old-style RMO mode, bounds check against RMLS */
|
||||
if (raddr >= limit) {
|
||||
return -1;
|
||||
}
|
||||
return raddr | env->spr[SPR_RMOR];
|
||||
}
|
||||
} else {
|
||||
slb = slb_lookup(cpu, addr);
|
||||
@ -997,168 +1068,12 @@ void ppc_hash64_tlb_flush_hpte(PowerPCCPU *cpu, target_ulong ptex,
|
||||
cpu->env.tlb_need_flush = TLB_NEED_GLOBAL_FLUSH | TLB_NEED_LOCAL_FLUSH;
|
||||
}
|
||||
|
||||
static void ppc_hash64_update_rmls(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint64_t lpcr = env->spr[SPR_LPCR];
|
||||
|
||||
/*
|
||||
* This is the full 4 bits encoding of POWER8. Previous
|
||||
* CPUs only support a subset of these but the filtering
|
||||
* is done when writing LPCR
|
||||
*/
|
||||
switch ((lpcr & LPCR_RMLS) >> LPCR_RMLS_SHIFT) {
|
||||
case 0x8: /* 32MB */
|
||||
env->rmls = 0x2000000ull;
|
||||
break;
|
||||
case 0x3: /* 64MB */
|
||||
env->rmls = 0x4000000ull;
|
||||
break;
|
||||
case 0x7: /* 128MB */
|
||||
env->rmls = 0x8000000ull;
|
||||
break;
|
||||
case 0x4: /* 256MB */
|
||||
env->rmls = 0x10000000ull;
|
||||
break;
|
||||
case 0x2: /* 1GB */
|
||||
env->rmls = 0x40000000ull;
|
||||
break;
|
||||
case 0x1: /* 16GB */
|
||||
env->rmls = 0x400000000ull;
|
||||
break;
|
||||
default:
|
||||
/* What to do here ??? */
|
||||
env->rmls = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ppc_hash64_update_vrma(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
const PPCHash64SegmentPageSizes *sps = NULL;
|
||||
target_ulong esid, vsid, lpcr;
|
||||
ppc_slb_t *slb = &env->vrma_slb;
|
||||
uint32_t vrmasd;
|
||||
int i;
|
||||
|
||||
/* First clear it */
|
||||
slb->esid = slb->vsid = 0;
|
||||
slb->sps = NULL;
|
||||
|
||||
/* Is VRMA enabled ? */
|
||||
lpcr = env->spr[SPR_LPCR];
|
||||
if (!(lpcr & LPCR_VPM0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make one up. Mostly ignore the ESID which will not be needed
|
||||
* for translation
|
||||
*/
|
||||
vsid = SLB_VSID_VRMA;
|
||||
vrmasd = (lpcr & LPCR_VRMASD) >> LPCR_VRMASD_SHIFT;
|
||||
vsid |= (vrmasd << 4) & (SLB_VSID_L | SLB_VSID_LP);
|
||||
esid = SLB_ESID_V;
|
||||
|
||||
for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
|
||||
const PPCHash64SegmentPageSizes *sps1 = &cpu->hash64_opts->sps[i];
|
||||
|
||||
if (!sps1->page_shift) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((vsid & SLB_VSID_LLP_MASK) == sps1->slb_enc) {
|
||||
sps = sps1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sps) {
|
||||
error_report("Bad page size encoding esid 0x"TARGET_FMT_lx
|
||||
" vsid 0x"TARGET_FMT_lx, esid, vsid);
|
||||
return;
|
||||
}
|
||||
|
||||
slb->vsid = vsid;
|
||||
slb->esid = esid;
|
||||
slb->sps = sps;
|
||||
}
|
||||
|
||||
void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint64_t lpcr = 0;
|
||||
|
||||
/* Filter out bits */
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_64B: /* 970 */
|
||||
if (val & 0x40) {
|
||||
lpcr |= LPCR_LPES0;
|
||||
}
|
||||
if (val & 0x8000000000000000ull) {
|
||||
lpcr |= LPCR_LPES1;
|
||||
}
|
||||
if (val & 0x20) {
|
||||
lpcr |= (0x4ull << LPCR_RMLS_SHIFT);
|
||||
}
|
||||
if (val & 0x4000000000000000ull) {
|
||||
lpcr |= (0x2ull << LPCR_RMLS_SHIFT);
|
||||
}
|
||||
if (val & 0x2000000000000000ull) {
|
||||
lpcr |= (0x1ull << LPCR_RMLS_SHIFT);
|
||||
}
|
||||
env->spr[SPR_RMOR] = ((lpcr >> 41) & 0xffffull) << 26;
|
||||
|
||||
/*
|
||||
* XXX We could also write LPID from HID4 here
|
||||
* but since we don't tag any translation on it
|
||||
* it doesn't actually matter
|
||||
*
|
||||
* XXX For proper emulation of 970 we also need
|
||||
* to dig HRMOR out of HID5
|
||||
*/
|
||||
break;
|
||||
case POWERPC_MMU_2_03: /* P5p */
|
||||
lpcr = val & (LPCR_RMLS | LPCR_ILE |
|
||||
LPCR_LPES0 | LPCR_LPES1 |
|
||||
LPCR_RMI | LPCR_HDICE);
|
||||
break;
|
||||
case POWERPC_MMU_2_06: /* P7 */
|
||||
lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
|
||||
LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
|
||||
LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
|
||||
LPCR_MER | LPCR_TC |
|
||||
LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE);
|
||||
break;
|
||||
case POWERPC_MMU_2_07: /* P8 */
|
||||
lpcr = val & (LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
|
||||
LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
|
||||
LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
|
||||
LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
|
||||
LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE);
|
||||
break;
|
||||
case POWERPC_MMU_3_00: /* P9 */
|
||||
lpcr = val & (LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
|
||||
(LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
|
||||
LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
|
||||
(LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
|
||||
LPCR_DEE | LPCR_OEE)) | LPCR_MER | LPCR_GTSE | LPCR_TC |
|
||||
LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE);
|
||||
/*
|
||||
* If we have a virtual hypervisor, we need to bring back RMLS. It
|
||||
* doesn't exist on an actual P9 but that's all we know how to
|
||||
* configure with softmmu at the moment
|
||||
*/
|
||||
if (cpu->vhyp) {
|
||||
lpcr |= (val & LPCR_RMLS);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
env->spr[SPR_LPCR] = lpcr;
|
||||
ppc_hash64_update_rmls(cpu);
|
||||
ppc_hash64_update_vrma(cpu);
|
||||
env->spr[SPR_LPCR] = val & pcc->lpcr_mask;
|
||||
}
|
||||
|
||||
void helper_store_lpcr(CPUPPCState *env, target_ulong val)
|
||||
|
@ -1938,15 +1938,17 @@ static void gen_rlwinm(DisasContext *ctx)
|
||||
me += 32;
|
||||
#endif
|
||||
mask = MASK(mb, me);
|
||||
if (sh == 0) {
|
||||
tcg_gen_andi_tl(t_ra, t_rs, mask);
|
||||
} else if (mask <= 0xffffffffu) {
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
tcg_gen_trunc_tl_i32(t0, t_rs);
|
||||
tcg_gen_rotli_i32(t0, t0, sh);
|
||||
tcg_gen_andi_i32(t0, t0, mask);
|
||||
tcg_gen_extu_i32_tl(t_ra, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
if (mask <= 0xffffffffu) {
|
||||
if (sh == 0) {
|
||||
tcg_gen_andi_tl(t_ra, t_rs, mask);
|
||||
} else {
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
tcg_gen_trunc_tl_i32(t0, t_rs);
|
||||
tcg_gen_rotli_i32(t0, t0, sh);
|
||||
tcg_gen_andi_i32(t0, t0, mask);
|
||||
tcg_gen_extu_i32_tl(t_ra, t0);
|
||||
tcg_temp_free_i32(t0);
|
||||
}
|
||||
} else {
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_deposit_i64(t_ra, t_rs, t_rs, 32, 32);
|
||||
|
@ -7895,25 +7895,21 @@ static void spr_write_lpcr(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
|
||||
}
|
||||
|
||||
static void spr_write_970_hid4(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
#if defined(TARGET_PPC64)
|
||||
spr_write_generic(ctx, sprn, gprn);
|
||||
gen_helper_store_lpcr(cpu_env, cpu_gpr[gprn]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
static void gen_spr_970_lpar(CPUPPCState *env)
|
||||
{
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Logical partitionning */
|
||||
/* PPC970: HID4 is effectively the LPCR */
|
||||
/*
|
||||
* PPC970: HID4 covers things later controlled by the LPCR and
|
||||
* RMOR in later CPUs, but with a different encoding. We only
|
||||
* support the 970 in "Apple mode" which has all hypervisor
|
||||
* facilities disabled by strapping, so we can basically just
|
||||
* ignore it
|
||||
*/
|
||||
spr_register(env, SPR_970_HID4, "HID4",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_970_hid4,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
#endif
|
||||
}
|
||||
@ -8019,12 +8015,16 @@ static void gen_spr_book3s_ids(CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register_hv(env, SPR_RMOR, "RMOR",
|
||||
spr_register_hv(env, SPR_HRMOR, "HRMOR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register_hv(env, SPR_HRMOR, "HRMOR",
|
||||
}
|
||||
|
||||
static void gen_spr_rmor(CPUPPCState *env)
|
||||
{
|
||||
spr_register_hv(env, SPR_RMOR, "RMOR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
@ -8476,6 +8476,8 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
|
||||
(1ull << MSR_DR) |
|
||||
(1ull << MSR_PMM) |
|
||||
(1ull << MSR_RI);
|
||||
pcc->lpcr_mask = LPCR_RMLS | LPCR_ILE | LPCR_LPES0 | LPCR_LPES1 |
|
||||
LPCR_RMI | LPCR_HDICE;
|
||||
pcc->mmu_model = POWERPC_MMU_2_03;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
||||
@ -8492,44 +8494,6 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
|
||||
pcc->l1_icache_size = 0x10000;
|
||||
}
|
||||
|
||||
/*
|
||||
* The CPU used to have a "compat" property which set the
|
||||
* compatibility mode PVR. However, this was conceptually broken - it
|
||||
* only makes sense on the pseries machine type (otherwise the guest
|
||||
* owns the PCR and can control the compatibility mode itself). It's
|
||||
* been replaced with the 'max-cpu-compat' property on the pseries
|
||||
* machine type. For backwards compatibility, pseries specially
|
||||
* parses the -cpu parameter and converts old compat= parameters into
|
||||
* the appropriate machine parameters. This stub implementation of
|
||||
* the parameter catches any uses on explicitly created CPUs.
|
||||
*/
|
||||
static void getset_compat_deprecated(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QNull *null = NULL;
|
||||
|
||||
if (!qtest_enabled()) {
|
||||
warn_report("CPU 'compat' property is deprecated and has no effect; "
|
||||
"use max-cpu-compat machine property instead");
|
||||
}
|
||||
visit_type_null(v, name, &null, NULL);
|
||||
qobject_unref(null);
|
||||
}
|
||||
|
||||
static const PropertyInfo ppc_compat_deprecated_propinfo = {
|
||||
.name = "str",
|
||||
.description = "compatibility mode (deprecated)",
|
||||
.get = getset_compat_deprecated,
|
||||
.set = getset_compat_deprecated,
|
||||
};
|
||||
static Property powerpc_servercpu_properties[] = {
|
||||
{
|
||||
.name = "compat",
|
||||
.info = &ppc_compat_deprecated_propinfo,
|
||||
},
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void init_proc_POWER7(CPUPPCState *env)
|
||||
{
|
||||
/* Common Registers */
|
||||
@ -8539,6 +8503,7 @@ static void init_proc_POWER7(CPUPPCState *env)
|
||||
|
||||
/* POWER7 Specific Registers */
|
||||
gen_spr_book3s_ids(env);
|
||||
gen_spr_rmor(env);
|
||||
gen_spr_amr(env);
|
||||
gen_spr_book3s_purr(env);
|
||||
gen_spr_power5p_common(env);
|
||||
@ -8611,7 +8576,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
||||
|
||||
dc->fw_name = "PowerPC,POWER7";
|
||||
dc->desc = "POWER7";
|
||||
device_class_set_props(dc, powerpc_servercpu_properties);
|
||||
pcc->pvr_match = ppc_pvr_match_power7;
|
||||
pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
|
||||
pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
|
||||
@ -8652,6 +8616,12 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
||||
(1ull << MSR_PMM) |
|
||||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_DPFD |
|
||||
LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
|
||||
LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2 |
|
||||
LPCR_MER | LPCR_TC |
|
||||
LPCR_LPES0 | LPCR_LPES1 | LPCR_HDICE;
|
||||
pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
|
||||
pcc->mmu_model = POWERPC_MMU_2_06;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
||||
@ -8668,7 +8638,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
|
||||
pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2;
|
||||
}
|
||||
|
||||
static void init_proc_POWER8(CPUPPCState *env)
|
||||
@ -8680,6 +8649,7 @@ static void init_proc_POWER8(CPUPPCState *env)
|
||||
|
||||
/* POWER8 Specific Registers */
|
||||
gen_spr_book3s_ids(env);
|
||||
gen_spr_rmor(env);
|
||||
gen_spr_amr(env);
|
||||
gen_spr_iamr(env);
|
||||
gen_spr_book3s_purr(env);
|
||||
@ -8776,7 +8746,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
|
||||
dc->fw_name = "PowerPC,POWER8";
|
||||
dc->desc = "POWER8";
|
||||
device_class_set_props(dc, powerpc_servercpu_properties);
|
||||
pcc->pvr_match = ppc_pvr_match_power8;
|
||||
pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
|
||||
pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
|
||||
@ -8804,7 +8773,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
|
||||
PPC2_TM | PPC2_PM_ISA206;
|
||||
pcc->msr_mask = (1ull << MSR_SF) |
|
||||
(1ull << MSR_SHV) |
|
||||
(1ull << MSR_HV) |
|
||||
(1ull << MSR_TM) |
|
||||
(1ull << MSR_VR) |
|
||||
(1ull << MSR_VSX) |
|
||||
@ -8823,6 +8792,13 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
(1ull << MSR_TS0) |
|
||||
(1ull << MSR_TS1) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->lpcr_mask = LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV |
|
||||
LPCR_DPFD | LPCR_VRMASD | LPCR_RMLS | LPCR_ILE |
|
||||
LPCR_AIL | LPCR_ONL | LPCR_P8_PECE0 | LPCR_P8_PECE1 |
|
||||
LPCR_P8_PECE2 | LPCR_P8_PECE3 | LPCR_P8_PECE4 |
|
||||
LPCR_MER | LPCR_TC | LPCR_LPES0 | LPCR_HDICE;
|
||||
pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
|
||||
LPCR_P8_PECE3 | LPCR_P8_PECE4;
|
||||
pcc->mmu_model = POWERPC_MMU_2_07;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
||||
@ -8840,8 +8816,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
|
||||
pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 |
|
||||
LPCR_P8_PECE3 | LPCR_P8_PECE4;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
@ -8988,7 +8962,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
|
||||
|
||||
dc->fw_name = "PowerPC,POWER9";
|
||||
dc->desc = "POWER9";
|
||||
device_class_set_props(dc, powerpc_servercpu_properties);
|
||||
pcc->pvr_match = ppc_pvr_match_power9;
|
||||
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
|
||||
pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
|
||||
@ -9017,7 +8990,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
|
||||
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
|
||||
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
|
||||
pcc->msr_mask = (1ull << MSR_SF) |
|
||||
(1ull << MSR_SHV) |
|
||||
(1ull << MSR_HV) |
|
||||
(1ull << MSR_TM) |
|
||||
(1ull << MSR_VR) |
|
||||
(1ull << MSR_VSX) |
|
||||
@ -9034,6 +9007,14 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
|
||||
(1ull << MSR_PMM) |
|
||||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
|
||||
(LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
|
||||
LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
|
||||
(LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
|
||||
LPCR_DEE | LPCR_OEE))
|
||||
| LPCR_MER | LPCR_GTSE | LPCR_TC |
|
||||
LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
|
||||
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
|
||||
pcc->mmu_model = POWERPC_MMU_3_00;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
|
||||
@ -9053,7 +9034,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
|
||||
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
@ -9198,7 +9178,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
|
||||
dc->fw_name = "PowerPC,POWER10";
|
||||
dc->desc = "POWER10";
|
||||
device_class_set_props(dc, powerpc_servercpu_properties);
|
||||
pcc->pvr_match = ppc_pvr_match_power10;
|
||||
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07 |
|
||||
PCR_COMPAT_3_00;
|
||||
@ -9228,7 +9207,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
|
||||
PPC2_TM | PPC2_ISA300 | PPC2_PRCNTL;
|
||||
pcc->msr_mask = (1ull << MSR_SF) |
|
||||
(1ull << MSR_SHV) |
|
||||
(1ull << MSR_HV) |
|
||||
(1ull << MSR_TM) |
|
||||
(1ull << MSR_VR) |
|
||||
(1ull << MSR_VSX) |
|
||||
@ -9245,6 +9224,14 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
(1ull << MSR_PMM) |
|
||||
(1ull << MSR_RI) |
|
||||
(1ull << MSR_LE);
|
||||
pcc->lpcr_mask = LPCR_VPM1 | LPCR_ISL | LPCR_KBV | LPCR_DPFD |
|
||||
(LPCR_PECE_U_MASK & LPCR_HVEE) | LPCR_ILE | LPCR_AIL |
|
||||
LPCR_UPRT | LPCR_EVIRT | LPCR_ONL | LPCR_HR | LPCR_LD |
|
||||
(LPCR_PECE_L_MASK & (LPCR_PDEE | LPCR_HDEE | LPCR_EEE |
|
||||
LPCR_DEE | LPCR_OEE))
|
||||
| LPCR_MER | LPCR_GTSE | LPCR_TC |
|
||||
LPCR_HEIC | LPCR_LPES0 | LPCR_HVICE | LPCR_HDICE;
|
||||
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
|
||||
pcc->mmu_model = POWERPC_MMU_3_00;
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
pcc->handle_mmu_fault = ppc64_v3_handle_mmu_fault;
|
||||
@ -9263,7 +9250,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
||||
pcc->l1_dcache_size = 0x8000;
|
||||
pcc->l1_icache_size = 0x8000;
|
||||
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;
|
||||
pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE;
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@ -10486,6 +10472,8 @@ static void ppc_cpu_parse_featurestr(const char *type, char *features,
|
||||
*s = '\0';
|
||||
for (i = 0; inpieces[i]; i++) {
|
||||
if (g_str_has_prefix(inpieces[i], "compat=")) {
|
||||
warn_report_once("CPU 'compat' property is deprecated; "
|
||||
"use max-cpu-compat machine property instead");
|
||||
compat_str = inpieces[i];
|
||||
continue;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ void qtest_spapr_shutdown(QOSState *qs);
|
||||
"cap-cfpc=broken," \
|
||||
"cap-sbbc=broken," \
|
||||
"cap-ibs=broken," \
|
||||
"cap-ccf-assist=off," \
|
||||
"cap-fwnmi-mce=off"
|
||||
"cap-ccf-assist=off,"
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user