2008-12-16 13:43:58 +03:00
|
|
|
/*
|
|
|
|
* PowerPC implementation of KVM hooks
|
|
|
|
*
|
|
|
|
* Copyright IBM Corp. 2007
|
2011-04-30 02:10:23 +04:00
|
|
|
* Copyright (C) 2011 Freescale Semiconductor, Inc.
|
2008-12-16 13:43:58 +03:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Jerone Young <jyoung5@us.ibm.com>
|
|
|
|
* Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
|
|
|
|
* Hollis Blanchard <hollisb@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
|
|
* See the COPYING file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:16:58 +03:00
|
|
|
#include "qemu/osdep.h"
|
2011-07-21 04:29:15 +04:00
|
|
|
#include <dirent.h>
|
2008-12-16 13:43:58 +03:00
|
|
|
#include <sys/ioctl.h>
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
#include <sys/vfs.h>
|
2008-12-16 13:43:58 +03:00
|
|
|
|
|
|
|
#include <linux/kvm.h>
|
|
|
|
|
2017-05-12 08:46:11 +03:00
|
|
|
#include "qapi/error.h"
|
2016-02-19 00:01:38 +03:00
|
|
|
#include "qemu/error-report.h"
|
2016-03-15 18:58:45 +03:00
|
|
|
#include "cpu.h"
|
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
When running with KVM on POWER, we are registering a "family" CPU
type for the host CPU that we are running on. For example, on all
POWER8-compatible hosts, we register a "POWER8" CPU type, so that
you can always start QEMU with "-cpu POWER8" there, without the
need to know whether you are running on a POWER8, POWER8E or POWER8NVL
host machine.
However, we also have a "POWER8" CPU alias in the ppc_cpu_aliases list
(that is mainly useful for TCG). This leads to two cosmetical drawbacks:
If the user runs QEMU with "-cpu ?", we always claim that POWER8 is an
"alias for POWER8_v2.0" - which is simply not true when running with
KVM on POWER. And when using the 'query-cpu-definitions' QMP call,
there are currently two entries for "POWER8", one for the alias, and
one for the additional registered type.
To solve the two problems, we should rather update the "family" alias
instead of registering a new types. We then only have one "POWER8"
CPU definition around, an alias, which also points to the right
destination.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1396536
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-01-31 16:11:58 +03:00
|
|
|
#include "cpu-models.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/timer.h"
|
2017-01-10 13:59:55 +03:00
|
|
|
#include "sysemu/hw_accel.h"
|
2008-12-16 13:43:58 +03:00
|
|
|
#include "kvm_ppc.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/cpus.h"
|
|
|
|
#include "sysemu/device_tree.h"
|
2013-03-12 04:31:18 +04:00
|
|
|
#include "mmu-hash64.h"
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/ppc/spapr.h"
|
2016-09-12 10:57:20 +03:00
|
|
|
#include "hw/ppc/spapr_cpu_core.h"
|
2019-08-12 08:23:48 +03:00
|
|
|
#include "hw/hw.h"
|
2014-05-01 14:37:09 +04:00
|
|
|
#include "hw/ppc/ppc.h"
|
2019-08-12 08:23:39 +03:00
|
|
|
#include "migration/qemu-file-types.h"
|
2013-02-24 22:16:21 +04:00
|
|
|
#include "sysemu/watchdog.h"
|
2014-02-04 08:12:34 +04:00
|
|
|
#include "trace.h"
|
2014-07-14 13:15:37 +04:00
|
|
|
#include "exec/gdbstub.h"
|
2015-04-08 14:30:58 +03:00
|
|
|
#include "exec/memattrs.h"
|
2017-03-02 05:36:11 +03:00
|
|
|
#include "exec/ram_addr.h"
|
2015-07-02 23:46:14 +03:00
|
|
|
#include "sysemu/hostmem.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/cutils.h"
|
Include qemu/main-loop.h less
In my "build everything" tree, changing qemu/main-loop.h triggers a
recompile of some 5600 out of 6600 objects (not counting tests and
objects that don't depend on qemu/osdep.h). It includes block/aio.h,
which in turn includes qemu/event_notifier.h, qemu/notify.h,
qemu/processor.h, qemu/qsp.h, qemu/queue.h, qemu/thread-posix.h,
qemu/thread.h, qemu/timer.h, and a few more.
Include qemu/main-loop.h only where it's needed. Touching it now
recompiles only some 1700 objects. For block/aio.h and
qemu/event_notifier.h, these numbers drop from 5600 to 2800. For the
others, they shrink only slightly.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190812052359.30071-21-armbru@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2019-08-12 08:23:50 +03:00
|
|
|
#include "qemu/main-loop.h"
|
2017-03-02 05:36:11 +03:00
|
|
|
#include "qemu/mmap-alloc.h"
|
2017-03-29 08:01:28 +03:00
|
|
|
#include "elf.h"
|
2017-03-20 02:46:43 +03:00
|
|
|
#include "sysemu/kvm_int.h"
|
2011-08-09 19:57:37 +04:00
|
|
|
|
2011-07-21 04:29:15 +04:00
|
|
|
#define PROC_DEVTREE_CPU "/proc/device-tree/cpus/"
|
|
|
|
|
2020-01-10 18:13:42 +03:00
|
|
|
#define DEBUG_RETURN_GUEST 0
|
|
|
|
#define DEBUG_RETURN_GDB 1
|
|
|
|
|
2011-01-21 23:48:17 +03:00
|
|
|
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
|
|
|
|
KVM_CAP_LAST_INFO
|
|
|
|
};
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
static int cap_interrupt_unset;
|
2011-04-30 02:10:23 +04:00
|
|
|
static int cap_segstate;
|
|
|
|
static int cap_booke_sregs;
|
2011-09-30 01:39:10 +04:00
|
|
|
static int cap_ppc_smt;
|
2017-08-18 08:50:22 +03:00
|
|
|
static int cap_ppc_smt_possible;
|
2011-09-30 01:39:12 +04:00
|
|
|
static int cap_spapr_tce;
|
2017-03-10 04:41:13 +03:00
|
|
|
static int cap_spapr_tce_64;
|
2014-05-27 09:36:30 +04:00
|
|
|
static int cap_spapr_multitce;
|
2014-06-10 09:39:21 +04:00
|
|
|
static int cap_spapr_vfio;
|
2012-09-12 20:57:09 +04:00
|
|
|
static int cap_hior;
|
2013-02-20 20:41:50 +04:00
|
|
|
static int cap_one_reg;
|
2013-03-30 10:40:49 +04:00
|
|
|
static int cap_epr;
|
2013-02-24 22:16:21 +04:00
|
|
|
static int cap_ppc_watchdog;
|
2013-04-07 23:08:22 +04:00
|
|
|
static int cap_papr;
|
2013-07-18 23:33:03 +04:00
|
|
|
static int cap_htab_fd;
|
2014-06-04 14:14:08 +04:00
|
|
|
static int cap_fixup_hcalls;
|
2016-09-28 14:16:30 +03:00
|
|
|
static int cap_htm; /* Hardware transactional memory support */
|
2017-03-20 02:46:44 +03:00
|
|
|
static int cap_mmu_radix;
|
|
|
|
static int cap_mmu_hash_v3;
|
2019-05-13 11:42:33 +03:00
|
|
|
static int cap_xive;
|
2017-07-12 10:56:55 +03:00
|
|
|
static int cap_resize_hpt;
|
2017-08-09 23:43:46 +03:00
|
|
|
static int cap_ppc_pvr_compat;
|
2018-01-19 07:59:59 +03:00
|
|
|
static int cap_ppc_safe_cache;
|
|
|
|
static int cap_ppc_safe_bounds_check;
|
|
|
|
static int cap_ppc_safe_indirect_branch;
|
2019-03-01 06:19:12 +03:00
|
|
|
static int cap_ppc_count_cache_flush_assist;
|
2018-10-08 06:25:39 +03:00
|
|
|
static int cap_ppc_nested_kvm_hv;
|
2019-03-01 05:43:16 +03:00
|
|
|
static int cap_large_decr;
|
2020-03-25 17:29:03 +03:00
|
|
|
static int cap_fwnmi;
|
2021-07-06 14:24:40 +03:00
|
|
|
static int cap_rpt_invalidate;
|
2023-05-15 19:02:16 +03:00
|
|
|
static int cap_ail_mode_3;
|
2010-08-30 15:49:15 +04:00
|
|
|
|
2014-07-14 13:15:35 +04:00
|
|
|
static uint32_t debug_inst_opcode;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Check whether we are running with KVM-PR (instead of KVM-HV). This
|
2016-09-29 13:48:06 +03:00
|
|
|
* should only be used for fallback tests - generally we should use
|
|
|
|
* explicit capabilities for the features we want, rather than
|
2019-03-21 13:47:25 +03:00
|
|
|
* assuming what is/isn't available depending on the KVM variant.
|
|
|
|
*/
|
2016-09-29 13:48:06 +03:00
|
|
|
static bool kvmppc_is_pr(KVMState *ks)
|
|
|
|
{
|
|
|
|
/* Assume KVM-PR if the GET_PVINFO capability is available */
|
2017-09-14 13:48:04 +03:00
|
|
|
return kvm_vm_check_extension(ks, KVM_CAP_PPC_GET_PVINFO) != 0;
|
2016-09-29 13:48:06 +03:00
|
|
|
}
|
|
|
|
|
spapr/kvm: Set default cpu model for all machine classes
We have to set the default model of all machine classes, not just for
the active one. Otherwise, "query-machines" will indicate the wrong
CPU model (e.g. "power9_v2.0-powerpc64-cpu" instead of
"host-powerpc64-cpu") as "default-cpu-type".
s390x already fixed this in de60a92e "s390x/kvm: Set default cpu model for
all machine classes". This patch applies a similar fix for the pseries-*
machine types on ppc64.
Doing a
{"execute":"query-machines"}
under KVM now results in
{
"hotpluggable-cpus": true,
"name": "pseries-4.2",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"is-default": true,
"cpu-max": 1024,
"deprecated": false,
"alias": "pseries"
},
{
"hotpluggable-cpus": true,
"name": "pseries-4.1",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"cpu-max": 1024,
"deprecated": false
},
...
Libvirt probes all machines via "-machine none,accel=kvm:tcg" and will
currently see the wrong CPU model under KVM.
Reported-by: Jiři Denemark <jdenemar@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
2019-10-30 19:20:35 +03:00
|
|
|
static int kvm_ppc_register_host_cpu_type(void);
|
2018-01-19 07:59:59 +03:00
|
|
|
static void kvmppc_get_cpu_characteristics(KVMState *s);
|
2019-03-01 05:43:16 +03:00
|
|
|
static int kvmppc_get_dec_bits(void);
|
2013-02-23 15:22:12 +04:00
|
|
|
|
2023-08-22 19:31:02 +03:00
|
|
|
int kvm_arch_get_default_type(MachineState *ms)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-04 18:43:51 +03:00
|
|
|
int kvm_arch_init(MachineState *ms, KVMState *s)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2010-08-30 15:49:15 +04:00
|
|
|
cap_interrupt_unset = kvm_check_extension(s, KVM_CAP_PPC_UNSET_IRQ);
|
2011-04-30 02:10:23 +04:00
|
|
|
cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE);
|
|
|
|
cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS);
|
2017-09-14 22:25:43 +03:00
|
|
|
cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE);
|
2011-09-30 01:39:12 +04:00
|
|
|
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
|
2017-03-10 04:41:13 +03:00
|
|
|
cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64);
|
2014-05-27 09:36:30 +04:00
|
|
|
cap_spapr_multitce = kvm_check_extension(s, KVM_CAP_SPAPR_MULTITCE);
|
2018-02-06 21:08:24 +03:00
|
|
|
cap_spapr_vfio = kvm_vm_check_extension(s, KVM_CAP_SPAPR_TCE_VFIO);
|
2013-02-20 20:41:50 +04:00
|
|
|
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
|
2012-09-12 20:57:09 +04:00
|
|
|
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
|
2013-03-30 10:40:49 +04:00
|
|
|
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
|
2013-02-24 22:16:21 +04:00
|
|
|
cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG);
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Note: we don't set cap_papr here, because this capability is
|
|
|
|
* only activated after this by kvmppc_set_papr()
|
|
|
|
*/
|
2017-09-14 22:25:43 +03:00
|
|
|
cap_htab_fd = kvm_vm_check_extension(s, KVM_CAP_PPC_HTAB_FD);
|
2014-06-04 14:14:08 +04:00
|
|
|
cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL);
|
2017-08-18 08:50:22 +03:00
|
|
|
cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT);
|
2016-09-28 14:16:30 +03:00
|
|
|
cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM);
|
2017-03-20 02:46:44 +03:00
|
|
|
cap_mmu_radix = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_RADIX);
|
|
|
|
cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3);
|
2019-05-13 11:42:33 +03:00
|
|
|
cap_xive = kvm_vm_check_extension(s, KVM_CAP_PPC_IRQ_XIVE);
|
2017-07-12 10:56:55 +03:00
|
|
|
cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT);
|
2018-01-19 07:59:59 +03:00
|
|
|
kvmppc_get_cpu_characteristics(s);
|
2018-10-08 06:25:39 +03:00
|
|
|
cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV);
|
2019-03-01 05:43:16 +03:00
|
|
|
cap_large_decr = kvmppc_get_dec_bits();
|
2020-03-25 17:29:03 +03:00
|
|
|
cap_fwnmi = kvm_vm_check_extension(s, KVM_CAP_PPC_FWNMI);
|
2017-08-09 23:43:46 +03:00
|
|
|
/*
|
|
|
|
* Note: setting it to false because there is not such capability
|
|
|
|
* in KVM at this moment.
|
|
|
|
*
|
|
|
|
* TODO: call kvm_vm_check_extension() with the right capability
|
2019-03-21 13:47:25 +03:00
|
|
|
* after the kernel starts implementing it.
|
|
|
|
*/
|
2017-08-09 23:43:46 +03:00
|
|
|
cap_ppc_pvr_compat = false;
|
2010-08-30 15:49:15 +04:00
|
|
|
|
2019-07-25 17:15:08 +03:00
|
|
|
if (!kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL)) {
|
|
|
|
error_report("KVM: Host kernel doesn't have level irq capability");
|
|
|
|
exit(1);
|
2010-08-30 15:49:15 +04:00
|
|
|
}
|
|
|
|
|
2021-07-06 14:24:40 +03:00
|
|
|
cap_rpt_invalidate = kvm_vm_check_extension(s, KVM_CAP_PPC_RPT_INVALIDATE);
|
2023-05-15 19:02:16 +03:00
|
|
|
cap_ail_mode_3 = kvm_vm_check_extension(s, KVM_CAP_PPC_AIL_MODE_3);
|
spapr/kvm: Set default cpu model for all machine classes
We have to set the default model of all machine classes, not just for
the active one. Otherwise, "query-machines" will indicate the wrong
CPU model (e.g. "power9_v2.0-powerpc64-cpu" instead of
"host-powerpc64-cpu") as "default-cpu-type".
s390x already fixed this in de60a92e "s390x/kvm: Set default cpu model for
all machine classes". This patch applies a similar fix for the pseries-*
machine types on ppc64.
Doing a
{"execute":"query-machines"}
under KVM now results in
{
"hotpluggable-cpus": true,
"name": "pseries-4.2",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"is-default": true,
"cpu-max": 1024,
"deprecated": false,
"alias": "pseries"
},
{
"hotpluggable-cpus": true,
"name": "pseries-4.1",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"cpu-max": 1024,
"deprecated": false
},
...
Libvirt probes all machines via "-machine none,accel=kvm:tcg" and will
currently see the wrong CPU model under KVM.
Reported-by: Jiři Denemark <jdenemar@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
2019-10-30 19:20:35 +03:00
|
|
|
kvm_ppc_register_host_cpu_type();
|
2013-02-23 15:22:12 +04:00
|
|
|
|
2008-12-16 13:43:58 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-13 13:17:12 +03:00
|
|
|
int kvm_arch_irqchip_create(KVMState *s)
|
2016-12-22 18:41:42 +03:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
static int kvm_arch_sync_sregs(PowerPCCPU *cpu)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2012-10-31 09:06:49 +04:00
|
|
|
CPUPPCState *cenv = &cpu->env;
|
|
|
|
CPUState *cs = CPU(cpu);
|
2009-07-17 15:51:43 +04:00
|
|
|
struct kvm_sregs sregs;
|
2011-04-12 03:34:34 +04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* What we're really trying to say is "if we're on BookE, we
|
|
|
|
* use the native PVR for now". This is the only sane way to
|
|
|
|
* check it though, so we potentially confuse users that they
|
|
|
|
* can run BookE guests on BookS. Let's hope nobody dares
|
|
|
|
* enough :)
|
|
|
|
*/
|
2011-04-12 03:34:34 +04:00
|
|
|
return 0;
|
|
|
|
} else {
|
2011-04-30 02:10:23 +04:00
|
|
|
if (!cap_segstate) {
|
2011-04-16 04:00:36 +04:00
|
|
|
fprintf(stderr, "kvm error: missing PVR setting capability\n");
|
|
|
|
return -ENOSYS;
|
2011-04-12 03:34:34 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_SREGS, &sregs);
|
2011-04-12 03:34:34 +04:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2009-07-17 15:51:43 +04:00
|
|
|
|
|
|
|
sregs.pvr = cenv->spr[SPR_PVR];
|
2012-10-31 09:06:49 +04:00
|
|
|
return kvm_vcpu_ioctl(cs, KVM_SET_SREGS, &sregs);
|
2011-04-12 03:34:34 +04:00
|
|
|
}
|
|
|
|
|
2011-08-31 15:26:56 +04:00
|
|
|
/* Set up a shared TLB array with KVM */
|
2012-10-31 09:06:49 +04:00
|
|
|
static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
|
2011-08-31 15:26:56 +04:00
|
|
|
{
|
2012-10-31 09:06:49 +04:00
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
CPUState *cs = CPU(cpu);
|
2011-08-31 15:26:56 +04:00
|
|
|
struct kvm_book3e_206_tlb_params params = {};
|
|
|
|
struct kvm_config_tlb cfg = {};
|
|
|
|
unsigned int entries = 0;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
if (!kvm_enabled() ||
|
2012-12-01 08:35:08 +04:00
|
|
|
!kvm_check_extension(cs->kvm_state, KVM_CAP_SW_TLB)) {
|
2011-08-31 15:26:56 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ARRAY_SIZE(params.tlb_sizes) == BOOKE206_MAX_TLBN);
|
|
|
|
|
|
|
|
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
|
|
|
|
params.tlb_sizes[i] = booke206_tlb_size(env, i);
|
|
|
|
params.tlb_ways[i] = booke206_tlb_ways(env, i);
|
|
|
|
entries += params.tlb_sizes[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(entries == env->nb_tlb);
|
|
|
|
assert(sizeof(struct kvm_book3e_206_tlb_entry) == sizeof(ppcmas_tlb_t));
|
|
|
|
|
|
|
|
env->tlb_dirty = true;
|
|
|
|
|
|
|
|
cfg.array = (uintptr_t)env->tlb.tlbm;
|
|
|
|
cfg.array_len = sizeof(ppcmas_tlb_t) * entries;
|
|
|
|
cfg.params = (uintptr_t)¶ms;
|
|
|
|
cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
|
|
|
|
|
2014-04-09 19:21:57 +04:00
|
|
|
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_SW_TLB, 0, (uintptr_t)&cfg);
|
2011-08-31 15:26:56 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
|
|
|
|
__func__, strerror(-ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
env->kvm_sw_tlb = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
|
|
|
|
#if defined(TARGET_PPC64)
|
2018-06-29 12:48:32 +03:00
|
|
|
static void kvm_get_smmu_info(struct kvm_ppc_smmu_info *info, Error **errp)
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
{
|
2018-06-29 12:48:16 +03:00
|
|
|
int ret;
|
2012-12-01 08:35:08 +04:00
|
|
|
|
2018-06-29 12:48:32 +03:00
|
|
|
assert(kvm_state != NULL);
|
|
|
|
|
|
|
|
if (!kvm_check_extension(kvm_state, KVM_CAP_PPC_GET_SMMU_INFO)) {
|
2018-06-29 12:48:16 +03:00
|
|
|
error_setg(errp, "KVM doesn't expose the MMU features it supports");
|
|
|
|
error_append_hint(errp, "Consider switching to a newer KVM\n");
|
|
|
|
return;
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
}
|
|
|
|
|
2018-06-29 12:48:32 +03:00
|
|
|
ret = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_SMMU_INFO, info);
|
2018-06-29 12:48:16 +03:00
|
|
|
if (ret == 0) {
|
|
|
|
return;
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
}
|
|
|
|
|
2018-06-29 12:48:16 +03:00
|
|
|
error_setg_errno(errp, -ret,
|
|
|
|
"KVM failed to provide the MMU features it supports");
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
}
|
|
|
|
|
2023-09-08 19:42:04 +03:00
|
|
|
static struct ppc_radix_page_info *kvmppc_get_radix_page_info(void)
|
2017-03-20 02:46:43 +03:00
|
|
|
{
|
2020-01-21 14:03:48 +03:00
|
|
|
KVMState *s = KVM_STATE(current_accel());
|
2017-03-20 02:46:43 +03:00
|
|
|
struct ppc_radix_page_info *radix_page_info;
|
2022-03-31 03:17:17 +03:00
|
|
|
struct kvm_ppc_rmmu_info rmmu_info = { };
|
2017-03-20 02:46:43 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!kvm_check_extension(s, KVM_CAP_PPC_MMU_RADIX)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (kvm_vm_ioctl(s, KVM_PPC_GET_RMMU_INFO, &rmmu_info)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
radix_page_info = g_malloc0(sizeof(*radix_page_info));
|
|
|
|
radix_page_info->count = 0;
|
|
|
|
for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
|
|
|
|
if (rmmu_info.ap_encodings[i]) {
|
|
|
|
radix_page_info->entries[i] = rmmu_info.ap_encodings[i];
|
|
|
|
radix_page_info->count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return radix_page_info;
|
|
|
|
}
|
|
|
|
|
2017-03-20 02:46:46 +03:00
|
|
|
target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu,
|
|
|
|
bool radix, bool gtse,
|
|
|
|
uint64_t proc_tbl)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
int ret;
|
|
|
|
uint64_t flags = 0;
|
|
|
|
struct kvm_ppc_mmuv3_cfg cfg = {
|
|
|
|
.process_table = proc_tbl,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (radix) {
|
|
|
|
flags |= KVM_PPC_MMUV3_RADIX;
|
|
|
|
}
|
|
|
|
if (gtse) {
|
|
|
|
flags |= KVM_PPC_MMUV3_GTSE;
|
|
|
|
}
|
|
|
|
cfg.flags = flags;
|
|
|
|
ret = kvm_vm_ioctl(cs->kvm_state, KVM_PPC_CONFIGURE_V3_MMU, &cfg);
|
|
|
|
switch (ret) {
|
|
|
|
case 0:
|
|
|
|
return H_SUCCESS;
|
|
|
|
case -EINVAL:
|
|
|
|
return H_PARAMETER;
|
|
|
|
case -ENODEV:
|
|
|
|
return H_NOT_AVAILABLE;
|
|
|
|
default:
|
|
|
|
return H_HARDWARE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-14 05:11:08 +03:00
|
|
|
bool kvmppc_hpt_needs_host_contiguous_pages(void)
|
|
|
|
{
|
|
|
|
static struct kvm_ppc_smmu_info smmu_info;
|
|
|
|
|
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-29 12:48:32 +03:00
|
|
|
kvm_get_smmu_info(&smmu_info, &error_fatal);
|
2018-06-14 05:11:08 +03:00
|
|
|
return !!(smmu_info.flags & KVM_PPC_PAGE_SIZES_REAL);
|
|
|
|
}
|
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
void kvm_check_mmu(PowerPCCPU *cpu, Error **errp)
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
{
|
2018-04-16 09:19:52 +03:00
|
|
|
struct kvm_ppc_smmu_info smmu_info;
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
int iq, ik, jq, jk;
|
2018-06-29 12:48:16 +03:00
|
|
|
Error *local_err = NULL;
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
/* For now, we only have anything to check on hash64 MMUs */
|
|
|
|
if (!cpu->hash64_opts || !kvm_enabled()) {
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-29 12:48:32 +03:00
|
|
|
kvm_get_smmu_info(&smmu_info, &local_err);
|
2018-06-29 12:48:16 +03:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
if (ppc_hash64_has(cpu, PPC_HASH64_1TSEG)
|
|
|
|
&& !(smmu_info.flags & KVM_PPC_1T_SEGMENTS)) {
|
|
|
|
error_setg(errp,
|
|
|
|
"KVM does not support 1TiB segments which guest expects");
|
|
|
|
return;
|
2017-02-15 12:21:44 +03:00
|
|
|
}
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
if (smmu_info.slb_size < cpu->hash64_opts->slb_size) {
|
|
|
|
error_setg(errp, "KVM only supports %u SLB entries, but guest needs %u",
|
|
|
|
smmu_info.slb_size, cpu->hash64_opts->slb_size);
|
|
|
|
return;
|
2015-10-22 10:30:59 +03:00
|
|
|
}
|
|
|
|
|
2014-05-11 20:37:00 +04:00
|
|
|
/*
|
2018-04-16 09:19:52 +03:00
|
|
|
* Verify that every pagesize supported by the cpu model is
|
|
|
|
* supported by KVM with the same encodings
|
2014-05-11 20:37:00 +04:00
|
|
|
*/
|
2018-04-16 09:19:52 +03:00
|
|
|
for (iq = 0; iq < ARRAY_SIZE(cpu->hash64_opts->sps); iq++) {
|
2018-03-23 05:31:52 +03:00
|
|
|
PPCHash64SegmentPageSizes *qsps = &cpu->hash64_opts->sps[iq];
|
2018-04-16 09:19:52 +03:00
|
|
|
struct kvm_ppc_one_seg_page_size *ksps;
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
for (ik = 0; ik < ARRAY_SIZE(smmu_info.sps); ik++) {
|
|
|
|
if (qsps->page_shift == smmu_info.sps[ik].page_shift) {
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-04-16 09:19:52 +03:00
|
|
|
if (ik >= ARRAY_SIZE(smmu_info.sps)) {
|
|
|
|
error_setg(errp, "KVM doesn't support for base page shift %u",
|
|
|
|
qsps->page_shift);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ksps = &smmu_info.sps[ik];
|
|
|
|
if (ksps->slb_enc != qsps->slb_enc) {
|
|
|
|
error_setg(errp,
|
|
|
|
"KVM uses SLB encoding 0x%x for page shift %u, but guest expects 0x%x",
|
|
|
|
ksps->slb_enc, ksps->page_shift, qsps->slb_enc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (jq = 0; jq < ARRAY_SIZE(qsps->enc); jq++) {
|
|
|
|
for (jk = 0; jk < ARRAY_SIZE(ksps->enc); jk++) {
|
|
|
|
if (qsps->enc[jq].page_shift == ksps->enc[jk].page_shift) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (jk >= ARRAY_SIZE(ksps->enc)) {
|
|
|
|
error_setg(errp, "KVM doesn't support page shift %u/%u",
|
|
|
|
qsps->enc[jq].page_shift, qsps->page_shift);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (qsps->enc[jq].pte_enc != ksps->enc[jk].pte_enc) {
|
|
|
|
error_setg(errp,
|
|
|
|
"KVM uses PTE encoding 0x%x for page shift %u/%u, but guest expects 0x%x",
|
|
|
|
ksps->enc[jk].pte_enc, qsps->enc[jq].page_shift,
|
|
|
|
qsps->page_shift, qsps->enc[jq].pte_enc);
|
|
|
|
return;
|
|
|
|
}
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 09:19:52 +03:00
|
|
|
if (ppc_hash64_has(cpu, PPC_HASH64_CI_LARGEPAGE)) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Mostly what guest pagesizes we can use are related to the
|
2018-04-16 09:19:52 +03:00
|
|
|
* host pages used to map guest RAM, which is handled in the
|
|
|
|
* platform code. Cache-Inhibited largepages (64k) however are
|
|
|
|
* used for I/O, so if they're mapped to the host at all it
|
|
|
|
* will be a normal mapping, not a special hugepage one used
|
2019-03-21 13:47:25 +03:00
|
|
|
* for RAM.
|
|
|
|
*/
|
2022-03-23 18:57:22 +03:00
|
|
|
if (qemu_real_host_page_size() < 0x10000) {
|
2018-04-16 09:19:52 +03:00
|
|
|
error_setg(errp,
|
|
|
|
"KVM can't supply 64kiB CI pages, which guest expects");
|
|
|
|
}
|
|
|
|
}
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
}
|
|
|
|
#endif /* !defined (TARGET_PPC64) */
|
|
|
|
|
2013-01-23 00:25:01 +04:00
|
|
|
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
|
|
|
|
{
|
2017-08-09 08:38:56 +03:00
|
|
|
return POWERPC_CPU(cpu)->vcpu_id;
|
2013-01-23 00:25:01 +04:00
|
|
|
}
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* e500 supports 2 h/w breakpoint and 2 watchpoint. book3s supports
|
|
|
|
* only 1 watchpoint, so array size of 4 is sufficient for now.
|
2014-07-14 13:15:37 +04:00
|
|
|
*/
|
|
|
|
#define MAX_HW_BKPTS 4
|
|
|
|
|
|
|
|
static struct HWBreakpoint {
|
|
|
|
target_ulong addr;
|
|
|
|
int type;
|
|
|
|
} hw_debug_points[MAX_HW_BKPTS];
|
|
|
|
|
|
|
|
static CPUWatchpoint hw_watchpoint;
|
|
|
|
|
|
|
|
/* Default there is no breakpoint and watchpoint supported */
|
|
|
|
static int max_hw_breakpoint;
|
|
|
|
static int max_hw_watchpoint;
|
|
|
|
static int nb_hw_breakpoint;
|
|
|
|
static int nb_hw_watchpoint;
|
|
|
|
|
|
|
|
static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
|
|
|
|
{
|
|
|
|
if (cenv->excp_model == POWERPC_EXCP_BOOKE) {
|
|
|
|
max_hw_breakpoint = 2;
|
|
|
|
max_hw_watchpoint = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((max_hw_breakpoint + max_hw_watchpoint) > MAX_HW_BKPTS) {
|
|
|
|
fprintf(stderr, "Error initializing h/w breakpoints\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
int kvm_arch_init_vcpu(CPUState *cs)
|
2011-04-12 03:34:34 +04:00
|
|
|
{
|
2012-10-31 09:57:49 +04:00
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
|
|
CPUPPCState *cenv = &cpu->env;
|
2011-04-12 03:34:34 +04:00
|
|
|
int ret;
|
|
|
|
|
ppc64: Rudimentary Support for extra page sizes on server CPUs
More recent Power server chips (i.e. based on the 64 bit hash MMU)
support more than just the traditional 4k and 16M page sizes. This
can get quite complicated, because which page sizes are supported,
which combinations are supported within an MMU segment and how these
page sizes are encoded both in the SLB entry and the hash PTE can vary
depending on the CPU model (they are not specified by the
architecture). In addition the firmware or hypervisor may not permit
use of certain page sizes, for various reasons. Whether various page
sizes are supported on KVM, for example, depends on whether the PR or
HV variant of KVM is in use, and on the page size of the memory
backing the guest's RAM.
This patch adds information to the CPUState and cpu defs to describe
the supported page sizes and encodings. Since TCG does not yet
support any extended page sizes, we just set this to NULL in the
static CPU definitions, expanding this to the default 4k and 16M page
sizes when we initialize the cpu state. When using KVM, however, we
instead determine available page sizes using the new
KVM_PPC_GET_SMMU_INFO call. For old kernels without that call, we use
some defaults, with some guesswork which should do the right thing for
existing HV and PR implementations. The fallback might not be correct
for future versions, but that's ok, because they'll have
KVM_PPC_GET_SMMU_INFO.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-06-18 23:56:25 +04:00
|
|
|
/* Synchronize sregs with kvm */
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_arch_sync_sregs(cpu);
|
2011-04-12 03:34:34 +04:00
|
|
|
if (ret) {
|
2016-02-19 00:01:56 +03:00
|
|
|
if (ret == -EINVAL) {
|
|
|
|
error_report("Register sync failed... If you're using kvm-hv.ko,"
|
|
|
|
" only \"-cpu host\" is possible");
|
|
|
|
}
|
2011-04-12 03:34:34 +04:00
|
|
|
return ret;
|
|
|
|
}
|
2009-07-17 15:51:43 +04:00
|
|
|
|
2011-08-31 15:26:56 +04:00
|
|
|
switch (cenv->mmu_model) {
|
|
|
|
case POWERPC_MMU_BOOKE206:
|
2016-09-29 13:48:07 +03:00
|
|
|
/* This target supports access to KVM's guest TLB */
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_booke206_tlb_init(cpu);
|
2011-08-31 15:26:56 +04:00
|
|
|
break;
|
2016-09-29 13:48:07 +03:00
|
|
|
case POWERPC_MMU_2_07:
|
|
|
|
if (!cap_htm && !kvmppc_is_pr(cs->kvm_state)) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* KVM-HV has transactional memory on POWER8 also without
|
|
|
|
* the KVM_CAP_PPC_HTM extension, so enable it here
|
2020-10-09 09:44:37 +03:00
|
|
|
* instead as long as it's available to userspace on the
|
2019-03-21 13:47:25 +03:00
|
|
|
* host.
|
|
|
|
*/
|
2017-03-29 08:01:28 +03:00
|
|
|
if (qemu_getauxval(AT_HWCAP2) & PPC_FEATURE2_HAS_HTM) {
|
|
|
|
cap_htm = true;
|
|
|
|
}
|
2016-09-29 13:48:07 +03:00
|
|
|
}
|
|
|
|
break;
|
2011-08-31 15:26:56 +04:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:35 +04:00
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_DEBUG_INST, &debug_inst_opcode);
|
2014-07-14 13:15:37 +04:00
|
|
|
kvmppc_hw_debug_points_init(cenv);
|
2014-07-14 13:15:35 +04:00
|
|
|
|
2009-07-17 15:51:43 +04:00
|
|
|
return ret;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2019-06-19 19:21:32 +03:00
|
|
|
int kvm_arch_destroy_vcpu(CPUState *cs)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
static void kvm_sw_tlb_put(PowerPCCPU *cpu)
|
2011-08-31 15:26:56 +04:00
|
|
|
{
|
2012-10-31 09:06:49 +04:00
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
CPUState *cs = CPU(cpu);
|
2011-08-31 15:26:56 +04:00
|
|
|
struct kvm_dirty_tlb dirty_tlb;
|
|
|
|
unsigned char *bitmap;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!env->kvm_sw_tlb) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitmap = g_malloc((env->nb_tlb + 7) / 8);
|
|
|
|
memset(bitmap, 0xFF, (env->nb_tlb + 7) / 8);
|
|
|
|
|
|
|
|
dirty_tlb.bitmap = (uintptr_t)bitmap;
|
|
|
|
dirty_tlb.num_dirty = env->nb_tlb;
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_DIRTY_TLB, &dirty_tlb);
|
2011-08-31 15:26:56 +04:00
|
|
|
if (ret) {
|
|
|
|
fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n",
|
|
|
|
__func__, strerror(-ret));
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(bitmap);
|
|
|
|
}
|
|
|
|
|
2013-02-20 20:41:50 +04:00
|
|
|
static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr)
|
|
|
|
{
|
2024-01-29 19:45:03 +03:00
|
|
|
CPUPPCState *env = cpu_env(cs);
|
2022-03-31 03:17:14 +03:00
|
|
|
/* Init 'val' to avoid "uninitialised value" Valgrind warnings */
|
2013-02-20 20:41:50 +04:00
|
|
|
union {
|
|
|
|
uint32_t u32;
|
|
|
|
uint64_t u64;
|
2022-03-31 03:17:14 +03:00
|
|
|
} val = { };
|
2013-02-20 20:41:50 +04:00
|
|
|
struct kvm_one_reg reg = {
|
|
|
|
.id = id,
|
|
|
|
.addr = (uintptr_t) &val,
|
|
|
|
};
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret != 0) {
|
2014-02-04 08:12:34 +04:00
|
|
|
trace_kvm_failed_spr_get(spr, strerror(errno));
|
2013-02-20 20:41:50 +04:00
|
|
|
} else {
|
|
|
|
switch (id & KVM_REG_SIZE_MASK) {
|
|
|
|
case KVM_REG_SIZE_U32:
|
|
|
|
env->spr[spr] = val.u32;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KVM_REG_SIZE_U64:
|
|
|
|
env->spr[spr] = val.u64;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Don't handle this size yet */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr)
|
|
|
|
{
|
2024-01-29 19:45:03 +03:00
|
|
|
CPUPPCState *env = cpu_env(cs);
|
2013-02-20 20:41:50 +04:00
|
|
|
union {
|
|
|
|
uint32_t u32;
|
|
|
|
uint64_t u64;
|
|
|
|
} val;
|
|
|
|
struct kvm_one_reg reg = {
|
|
|
|
.id = id,
|
|
|
|
.addr = (uintptr_t) &val,
|
|
|
|
};
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
switch (id & KVM_REG_SIZE_MASK) {
|
|
|
|
case KVM_REG_SIZE_U32:
|
|
|
|
val.u32 = env->spr[spr];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KVM_REG_SIZE_U64:
|
|
|
|
val.u64 = env->spr[spr];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Don't handle this size yet */
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret != 0) {
|
2014-02-04 08:12:34 +04:00
|
|
|
trace_kvm_failed_spr_set(spr, strerror(errno));
|
2013-02-20 20:41:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-20 20:41:51 +04:00
|
|
|
static int kvm_put_fp(CPUState *cs)
|
|
|
|
{
|
2024-01-29 19:45:03 +03:00
|
|
|
CPUPPCState *env = cpu_env(cs);
|
2013-02-20 20:41:51 +04:00
|
|
|
struct kvm_one_reg reg;
|
|
|
|
int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (env->insns_flags & PPC_FLOAT) {
|
|
|
|
uint64_t fpscr = env->fpscr;
|
|
|
|
bool vsx = !!(env->insns_flags2 & PPC2_VSX);
|
|
|
|
|
|
|
|
reg.id = KVM_REG_PPC_FPSCR;
|
|
|
|
reg.addr = (uintptr_t)&fpscr;
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_fpscr_set(strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
uint64_t vsr[2];
|
2024-01-29 19:44:43 +03:00
|
|
|
uint64_t *fpr = cpu_fpr_ptr(env, i);
|
|
|
|
uint64_t *vsrl = cpu_vsrl_ptr(env, i);
|
2013-02-20 20:41:51 +04:00
|
|
|
|
2022-03-23 18:57:17 +03:00
|
|
|
#if HOST_BIG_ENDIAN
|
2019-01-02 12:14:22 +03:00
|
|
|
vsr[0] = float64_val(*fpr);
|
|
|
|
vsr[1] = *vsrl;
|
2016-01-15 18:00:12 +03:00
|
|
|
#else
|
2019-01-02 12:14:22 +03:00
|
|
|
vsr[0] = *vsrl;
|
|
|
|
vsr[1] = float64_val(*fpr);
|
2016-01-15 18:00:12 +03:00
|
|
|
#endif
|
2013-02-20 20:41:51 +04:00
|
|
|
reg.addr = (uintptr_t) &vsr;
|
|
|
|
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_fp_set(vsx ? "VSR" : "FPR", i,
|
|
|
|
strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (env->insns_flags & PPC_ALTIVEC) {
|
|
|
|
reg.id = KVM_REG_PPC_VSCR;
|
|
|
|
reg.addr = (uintptr_t)&env->vscr;
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vscr_set(strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
reg.id = KVM_REG_PPC_VR(i);
|
2019-01-02 12:14:22 +03:00
|
|
|
reg.addr = (uintptr_t)cpu_avr_ptr(env, i);
|
2013-02-20 20:41:51 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vr_set(i, strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvm_get_fp(CPUState *cs)
|
|
|
|
{
|
2024-01-29 19:45:03 +03:00
|
|
|
CPUPPCState *env = cpu_env(cs);
|
2013-02-20 20:41:51 +04:00
|
|
|
struct kvm_one_reg reg;
|
|
|
|
int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (env->insns_flags & PPC_FLOAT) {
|
|
|
|
uint64_t fpscr;
|
|
|
|
bool vsx = !!(env->insns_flags2 & PPC2_VSX);
|
|
|
|
|
|
|
|
reg.id = KVM_REG_PPC_FPSCR;
|
|
|
|
reg.addr = (uintptr_t)&fpscr;
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_fpscr_get(strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
} else {
|
|
|
|
env->fpscr = fpscr;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
uint64_t vsr[2];
|
2024-01-29 19:44:43 +03:00
|
|
|
uint64_t *fpr = cpu_fpr_ptr(env, i);
|
|
|
|
uint64_t *vsrl = cpu_vsrl_ptr(env, i);
|
2013-02-20 20:41:51 +04:00
|
|
|
|
|
|
|
reg.addr = (uintptr_t) &vsr;
|
|
|
|
reg.id = vsx ? KVM_REG_PPC_VSR(i) : KVM_REG_PPC_FPR(i);
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_fp_get(vsx ? "VSR" : "FPR", i,
|
|
|
|
strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
} else {
|
2022-03-23 18:57:17 +03:00
|
|
|
#if HOST_BIG_ENDIAN
|
2019-01-02 12:14:22 +03:00
|
|
|
*fpr = vsr[0];
|
2013-02-20 20:41:51 +04:00
|
|
|
if (vsx) {
|
2019-01-02 12:14:22 +03:00
|
|
|
*vsrl = vsr[1];
|
2013-02-20 20:41:51 +04:00
|
|
|
}
|
2016-01-15 18:00:12 +03:00
|
|
|
#else
|
2019-01-02 12:14:22 +03:00
|
|
|
*fpr = vsr[1];
|
2016-01-15 18:00:12 +03:00
|
|
|
if (vsx) {
|
2019-01-02 12:14:22 +03:00
|
|
|
*vsrl = vsr[0];
|
2016-01-15 18:00:12 +03:00
|
|
|
}
|
|
|
|
#endif
|
2013-02-20 20:41:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (env->insns_flags & PPC_ALTIVEC) {
|
|
|
|
reg.id = KVM_REG_PPC_VSCR;
|
|
|
|
reg.addr = (uintptr_t)&env->vscr;
|
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vscr_get(strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
|
|
reg.id = KVM_REG_PPC_VR(i);
|
2019-01-02 12:14:22 +03:00
|
|
|
reg.addr = (uintptr_t)cpu_avr_ptr(env, i);
|
2013-02-20 20:41:51 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vr_get(i, strerror(errno));
|
2013-02-20 20:41:51 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-07 23:08:22 +04:00
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
static int kvm_get_vpa(CPUState *cs)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
spapr: Use CamelCase properly
The qemu coding standard is to use CamelCase for type and structure names,
and the pseries code follows that... sort of. There are quite a lot of
places where we bend the rules in order to preserve the capitalization of
internal acronyms like "PHB", "TCE", "DIMM" and most commonly "sPAPR".
That was a bad idea - it frequently leads to names ending up with hard to
read clusters of capital letters, and means they don't catch the eye as
type identifiers, which is kind of the point of the CamelCase convention in
the first place.
In short, keeping type identifiers look like CamelCase is more important
than preserving standard capitalization of internal "words". So, this
patch renames a heap of spapr internal type names to a more standard
CamelCase.
In addition to case changes, we also make some other identifier renames:
VIOsPAPR* -> SpaprVio*
The reverse word ordering was only ever used to mitigate the capital
cluster, so revert to the natural ordering.
VIOsPAPRVTYDevice -> SpaprVioVty
VIOsPAPRVLANDevice -> SpaprVioVlan
Brevity, since the "Device" didn't add useful information
sPAPRDRConnector -> SpaprDrc
sPAPRDRConnectorClass -> SpaprDrcClass
Brevity, and makes it clearer this is the same thing as a "DRC"
mentioned in many other places in the code
This is 100% a mechanical search-and-replace patch. It will, however,
conflict with essentially any and all outstanding patches touching the
spapr code.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-03-06 07:35:37 +03:00
|
|
|
SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
|
2013-04-07 23:08:22 +04:00
|
|
|
struct kvm_one_reg reg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
reg.id = KVM_REG_PPC_VPA_ADDR;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vpa_addr_get(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
assert((uintptr_t)&spapr_cpu->slb_shadow_size
|
|
|
|
== ((uintptr_t)&spapr_cpu->slb_shadow_addr + 8));
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_SLB;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_slb_get(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
assert((uintptr_t)&spapr_cpu->dtl_size
|
|
|
|
== ((uintptr_t)&spapr_cpu->dtl_addr + 8));
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_DTL;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->dtl_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_dtl_get(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvm_put_vpa(CPUState *cs)
|
|
|
|
{
|
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
spapr: Use CamelCase properly
The qemu coding standard is to use CamelCase for type and structure names,
and the pseries code follows that... sort of. There are quite a lot of
places where we bend the rules in order to preserve the capitalization of
internal acronyms like "PHB", "TCE", "DIMM" and most commonly "sPAPR".
That was a bad idea - it frequently leads to names ending up with hard to
read clusters of capital letters, and means they don't catch the eye as
type identifiers, which is kind of the point of the CamelCase convention in
the first place.
In short, keeping type identifiers look like CamelCase is more important
than preserving standard capitalization of internal "words". So, this
patch renames a heap of spapr internal type names to a more standard
CamelCase.
In addition to case changes, we also make some other identifier renames:
VIOsPAPR* -> SpaprVio*
The reverse word ordering was only ever used to mitigate the capital
cluster, so revert to the natural ordering.
VIOsPAPRVTYDevice -> SpaprVioVty
VIOsPAPRVLANDevice -> SpaprVioVlan
Brevity, since the "Device" didn't add useful information
sPAPRDRConnector -> SpaprDrc
sPAPRDRConnectorClass -> SpaprDrcClass
Brevity, and makes it clearer this is the same thing as a "DRC"
mentioned in many other places in the code
This is 100% a mechanical search-and-replace patch. It will, however,
conflict with essentially any and all outstanding patches touching the
spapr code.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2019-03-06 07:35:37 +03:00
|
|
|
SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
|
2013-04-07 23:08:22 +04:00
|
|
|
struct kvm_one_reg reg;
|
|
|
|
int ret;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* SLB shadow or DTL can't be registered unless a master VPA is
|
2013-04-07 23:08:22 +04:00
|
|
|
* registered. That means when restoring state, if a VPA *is*
|
|
|
|
* registered, we need to set that up first. If not, we need to
|
2019-03-21 13:47:25 +03:00
|
|
|
* deregister the others before deregistering the master VPA
|
|
|
|
*/
|
2018-06-13 09:22:18 +03:00
|
|
|
assert(spapr_cpu->vpa_addr
|
|
|
|
|| !(spapr_cpu->slb_shadow_addr || spapr_cpu->dtl_addr));
|
2013-04-07 23:08:22 +04:00
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
if (spapr_cpu->vpa_addr) {
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_ADDR;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_vpa_addr_set(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
assert((uintptr_t)&spapr_cpu->slb_shadow_size
|
|
|
|
== ((uintptr_t)&spapr_cpu->slb_shadow_addr + 8));
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_SLB;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->slb_shadow_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_slb_set(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
assert((uintptr_t)&spapr_cpu->dtl_size
|
|
|
|
== ((uintptr_t)&spapr_cpu->dtl_addr + 8));
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_DTL;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->dtl_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_dtl_set(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:22:18 +03:00
|
|
|
if (!spapr_cpu->vpa_addr) {
|
2013-04-07 23:08:22 +04:00
|
|
|
reg.id = KVM_REG_PPC_VPA_ADDR;
|
2018-06-13 09:22:18 +03:00
|
|
|
reg.addr = (uintptr_t)&spapr_cpu->vpa_addr;
|
2013-04-07 23:08:22 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
if (ret < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_null_vpa_addr_set(strerror(errno));
|
2013-04-07 23:08:22 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* TARGET_PPC64 */
|
|
|
|
|
2016-03-08 03:33:46 +03:00
|
|
|
int kvmppc_put_books_sregs(PowerPCCPU *cpu)
|
2016-03-09 03:58:33 +03:00
|
|
|
{
|
|
|
|
CPUPPCState *env = &cpu->env;
|
2022-03-31 03:17:16 +03:00
|
|
|
struct kvm_sregs sregs = { };
|
2016-03-09 03:58:33 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
sregs.pvr = env->spr[SPR_PVR];
|
|
|
|
|
2017-09-25 14:00:02 +03:00
|
|
|
if (cpu->vhyp) {
|
|
|
|
PPCVirtualHypervisorClass *vhc =
|
|
|
|
PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
|
|
|
sregs.u.s.sdr1 = vhc->encode_hpt_for_kvm_pr(cpu->vhyp);
|
|
|
|
} else {
|
|
|
|
sregs.u.s.sdr1 = env->spr[SPR_SDR1];
|
|
|
|
}
|
2016-03-09 03:58:33 +03:00
|
|
|
|
|
|
|
/* Sync SLB */
|
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
|
|
|
|
sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid;
|
|
|
|
if (env->slb[i].esid & SLB_ESID_V) {
|
|
|
|
sregs.u.s.ppc64.slb[i].slbe |= i;
|
|
|
|
}
|
|
|
|
sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Sync SRs */
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
sregs.u.s.ppc32.sr[i] = env->sr[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sync BATs */
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
/* Beware. We have to swap upper and lower bits here */
|
|
|
|
sregs.u.s.ppc32.dbat[i] = ((uint64_t)env->DBAT[0][i] << 32)
|
|
|
|
| env->DBAT[1][i];
|
|
|
|
sregs.u.s.ppc32.ibat[i] = ((uint64_t)env->IBAT[0][i] << 32)
|
|
|
|
| env->IBAT[1][i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
int kvm_arch_put_registers(CPUState *cs, int level)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2012-10-31 09:57:49 +04:00
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
2008-12-16 13:43:58 +03:00
|
|
|
struct kvm_regs regs;
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s);
|
|
|
|
if (ret < 0) {
|
2008-12-16 13:43:58 +03:00
|
|
|
return ret;
|
2012-10-31 09:06:49 +04:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
|
|
|
regs.ctr = env->ctr;
|
|
|
|
regs.lr = env->lr;
|
2013-02-20 11:52:13 +04:00
|
|
|
regs.xer = cpu_read_xer(env);
|
2008-12-16 13:43:58 +03:00
|
|
|
regs.msr = env->msr;
|
|
|
|
regs.pc = env->nip;
|
|
|
|
|
|
|
|
regs.srr0 = env->spr[SPR_SRR0];
|
|
|
|
regs.srr1 = env->spr[SPR_SRR1];
|
|
|
|
|
|
|
|
regs.sprg0 = env->spr[SPR_SPRG0];
|
|
|
|
regs.sprg1 = env->spr[SPR_SPRG1];
|
|
|
|
regs.sprg2 = env->spr[SPR_SPRG2];
|
|
|
|
regs.sprg3 = env->spr[SPR_SPRG3];
|
|
|
|
regs.sprg4 = env->spr[SPR_SPRG4];
|
|
|
|
regs.sprg5 = env->spr[SPR_SPRG5];
|
|
|
|
regs.sprg6 = env->spr[SPR_SPRG6];
|
|
|
|
regs.sprg7 = env->spr[SPR_SPRG7];
|
|
|
|
|
2011-04-30 02:10:23 +04:00
|
|
|
regs.pid = env->spr[SPR_BOOKE_PID];
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
for (i = 0; i < 32; i++) {
|
2008-12-16 13:43:58 +03:00
|
|
|
regs.gpr[i] = env->gpr[i];
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2023-05-03 12:36:18 +03:00
|
|
|
regs.cr = ppc_get_cr(env);
|
2013-06-15 05:51:51 +04:00
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, ®s);
|
2019-03-21 13:47:25 +03:00
|
|
|
if (ret < 0) {
|
2008-12-16 13:43:58 +03:00
|
|
|
return ret;
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2013-02-20 20:41:51 +04:00
|
|
|
kvm_put_fp(cs);
|
|
|
|
|
2011-08-31 15:26:56 +04:00
|
|
|
if (env->tlb_dirty) {
|
2012-10-31 09:06:49 +04:00
|
|
|
kvm_sw_tlb_put(cpu);
|
2011-08-31 15:26:56 +04:00
|
|
|
env->tlb_dirty = false;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:57:09 +04:00
|
|
|
if (cap_segstate && (level >= KVM_PUT_RESET_STATE)) {
|
2016-03-09 03:58:33 +03:00
|
|
|
ret = kvmppc_put_books_sregs(cpu);
|
|
|
|
if (ret < 0) {
|
2012-09-12 20:57:09 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap_hior && (level >= KVM_PUT_RESET_STATE)) {
|
2013-02-20 20:41:50 +04:00
|
|
|
kvm_put_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR);
|
|
|
|
}
|
2012-09-12 20:57:09 +04:00
|
|
|
|
2013-02-20 20:41:50 +04:00
|
|
|
if (cap_one_reg) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* We deliberately ignore errors here, for kernels which have
|
2013-02-20 20:41:50 +04:00
|
|
|
* the ONE_REG calls, but don't support the specific
|
|
|
|
* registers, there's a reasonable chance things will still
|
2019-03-21 13:47:25 +03:00
|
|
|
* work, at least until we try to migrate.
|
|
|
|
*/
|
2013-02-20 20:41:50 +04:00
|
|
|
for (i = 0; i < 1024; i++) {
|
|
|
|
uint64_t id = env->spr_cb[i].one_reg_id;
|
|
|
|
|
|
|
|
if (id != 0) {
|
|
|
|
kvm_put_one_spr(cs, id, i);
|
|
|
|
}
|
2012-09-12 20:57:09 +04:00
|
|
|
}
|
2013-04-07 23:08:22 +04:00
|
|
|
|
|
|
|
#ifdef TARGET_PPC64
|
2022-05-05 00:05:37 +03:00
|
|
|
if (FIELD_EX64(env->msr, MSR, TS)) {
|
2014-06-04 16:51:00 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) {
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]);
|
|
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) {
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]);
|
|
|
|
}
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr);
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar);
|
|
|
|
}
|
|
|
|
|
2013-04-07 23:08:22 +04:00
|
|
|
if (cap_papr) {
|
|
|
|
if (kvm_put_vpa(cs) < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_put_vpa();
|
2013-04-07 23:08:22 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-01 14:37:09 +04:00
|
|
|
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
|
2019-09-23 11:41:10 +03:00
|
|
|
|
|
|
|
if (level > KVM_PUT_RUNTIME_STATE) {
|
|
|
|
kvm_put_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
|
|
|
|
}
|
2013-04-07 23:08:22 +04:00
|
|
|
#endif /* TARGET_PPC64 */
|
2012-09-12 20:57:09 +04:00
|
|
|
}
|
|
|
|
|
2008-12-16 13:43:58 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:36 +04:00
|
|
|
static void kvm_sync_excp(CPUPPCState *env, int vector, int ivor)
|
|
|
|
{
|
|
|
|
env->excp_vectors[vector] = env->spr[ivor] + env->spr[SPR_BOOKE_IVPR];
|
|
|
|
}
|
|
|
|
|
2016-03-09 03:58:33 +03:00
|
|
|
static int kvmppc_get_booke_sregs(PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
struct kvm_sregs sregs;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_BASE) {
|
|
|
|
env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
|
|
|
|
env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
|
|
|
|
env->spr[SPR_BOOKE_ESR] = sregs.u.e.esr;
|
|
|
|
env->spr[SPR_BOOKE_DEAR] = sregs.u.e.dear;
|
|
|
|
env->spr[SPR_BOOKE_MCSR] = sregs.u.e.mcsr;
|
|
|
|
env->spr[SPR_BOOKE_TSR] = sregs.u.e.tsr;
|
|
|
|
env->spr[SPR_BOOKE_TCR] = sregs.u.e.tcr;
|
|
|
|
env->spr[SPR_DECR] = sregs.u.e.dec;
|
|
|
|
env->spr[SPR_TBL] = sregs.u.e.tb & 0xffffffff;
|
|
|
|
env->spr[SPR_TBU] = sregs.u.e.tb >> 32;
|
|
|
|
env->spr[SPR_VRSAVE] = sregs.u.e.vrsave;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_ARCH206) {
|
|
|
|
env->spr[SPR_BOOKE_PIR] = sregs.u.e.pir;
|
|
|
|
env->spr[SPR_BOOKE_MCSRR0] = sregs.u.e.mcsrr0;
|
|
|
|
env->spr[SPR_BOOKE_MCSRR1] = sregs.u.e.mcsrr1;
|
|
|
|
env->spr[SPR_BOOKE_DECAR] = sregs.u.e.decar;
|
|
|
|
env->spr[SPR_BOOKE_IVPR] = sregs.u.e.ivpr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_64) {
|
|
|
|
env->spr[SPR_BOOKE_EPCR] = sregs.u.e.epcr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_SPRG8) {
|
|
|
|
env->spr[SPR_BOOKE_SPRG8] = sregs.u.e.sprg8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_IVOR) {
|
|
|
|
env->spr[SPR_BOOKE_IVOR0] = sregs.u.e.ivor_low[0];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_CRITICAL, SPR_BOOKE_IVOR0);
|
|
|
|
env->spr[SPR_BOOKE_IVOR1] = sregs.u.e.ivor_low[1];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_MCHECK, SPR_BOOKE_IVOR1);
|
|
|
|
env->spr[SPR_BOOKE_IVOR2] = sregs.u.e.ivor_low[2];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DSI, SPR_BOOKE_IVOR2);
|
|
|
|
env->spr[SPR_BOOKE_IVOR3] = sregs.u.e.ivor_low[3];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_ISI, SPR_BOOKE_IVOR3);
|
|
|
|
env->spr[SPR_BOOKE_IVOR4] = sregs.u.e.ivor_low[4];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_EXTERNAL, SPR_BOOKE_IVOR4);
|
|
|
|
env->spr[SPR_BOOKE_IVOR5] = sregs.u.e.ivor_low[5];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_ALIGN, SPR_BOOKE_IVOR5);
|
|
|
|
env->spr[SPR_BOOKE_IVOR6] = sregs.u.e.ivor_low[6];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_PROGRAM, SPR_BOOKE_IVOR6);
|
|
|
|
env->spr[SPR_BOOKE_IVOR7] = sregs.u.e.ivor_low[7];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_FPU, SPR_BOOKE_IVOR7);
|
|
|
|
env->spr[SPR_BOOKE_IVOR8] = sregs.u.e.ivor_low[8];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_SYSCALL, SPR_BOOKE_IVOR8);
|
|
|
|
env->spr[SPR_BOOKE_IVOR9] = sregs.u.e.ivor_low[9];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_APU, SPR_BOOKE_IVOR9);
|
|
|
|
env->spr[SPR_BOOKE_IVOR10] = sregs.u.e.ivor_low[10];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DECR, SPR_BOOKE_IVOR10);
|
|
|
|
env->spr[SPR_BOOKE_IVOR11] = sregs.u.e.ivor_low[11];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_FIT, SPR_BOOKE_IVOR11);
|
|
|
|
env->spr[SPR_BOOKE_IVOR12] = sregs.u.e.ivor_low[12];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_WDT, SPR_BOOKE_IVOR12);
|
|
|
|
env->spr[SPR_BOOKE_IVOR13] = sregs.u.e.ivor_low[13];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DTLB, SPR_BOOKE_IVOR13);
|
|
|
|
env->spr[SPR_BOOKE_IVOR14] = sregs.u.e.ivor_low[14];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_ITLB, SPR_BOOKE_IVOR14);
|
|
|
|
env->spr[SPR_BOOKE_IVOR15] = sregs.u.e.ivor_low[15];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DEBUG, SPR_BOOKE_IVOR15);
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_SPE) {
|
|
|
|
env->spr[SPR_BOOKE_IVOR32] = sregs.u.e.ivor_high[0];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_SPEU, SPR_BOOKE_IVOR32);
|
|
|
|
env->spr[SPR_BOOKE_IVOR33] = sregs.u.e.ivor_high[1];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_EFPDI, SPR_BOOKE_IVOR33);
|
|
|
|
env->spr[SPR_BOOKE_IVOR34] = sregs.u.e.ivor_high[2];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_EFPRI, SPR_BOOKE_IVOR34);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_PM) {
|
|
|
|
env->spr[SPR_BOOKE_IVOR35] = sregs.u.e.ivor_high[3];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_EPERFM, SPR_BOOKE_IVOR35);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_PC) {
|
|
|
|
env->spr[SPR_BOOKE_IVOR36] = sregs.u.e.ivor_high[4];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DOORI, SPR_BOOKE_IVOR36);
|
|
|
|
env->spr[SPR_BOOKE_IVOR37] = sregs.u.e.ivor_high[5];
|
|
|
|
kvm_sync_excp(env, POWERPC_EXCP_DOORCI, SPR_BOOKE_IVOR37);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_ARCH206_MMU) {
|
|
|
|
env->spr[SPR_BOOKE_MAS0] = sregs.u.e.mas0;
|
|
|
|
env->spr[SPR_BOOKE_MAS1] = sregs.u.e.mas1;
|
|
|
|
env->spr[SPR_BOOKE_MAS2] = sregs.u.e.mas2;
|
|
|
|
env->spr[SPR_BOOKE_MAS3] = sregs.u.e.mas7_3 & 0xffffffff;
|
|
|
|
env->spr[SPR_BOOKE_MAS4] = sregs.u.e.mas4;
|
|
|
|
env->spr[SPR_BOOKE_MAS6] = sregs.u.e.mas6;
|
|
|
|
env->spr[SPR_BOOKE_MAS7] = sregs.u.e.mas7_3 >> 32;
|
|
|
|
env->spr[SPR_MMUCFG] = sregs.u.e.mmucfg;
|
|
|
|
env->spr[SPR_BOOKE_TLB0CFG] = sregs.u.e.tlbcfg[0];
|
|
|
|
env->spr[SPR_BOOKE_TLB1CFG] = sregs.u.e.tlbcfg[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_EXP) {
|
|
|
|
env->spr[SPR_BOOKE_EPR] = sregs.u.e.epr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.features & KVM_SREGS_E_PD) {
|
|
|
|
env->spr[SPR_BOOKE_EPLC] = sregs.u.e.eplc;
|
|
|
|
env->spr[SPR_BOOKE_EPSC] = sregs.u.e.epsc;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sregs.u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
|
|
|
|
env->spr[SPR_E500_SVR] = sregs.u.e.impl.fsl.svr;
|
|
|
|
env->spr[SPR_Exxx_MCAR] = sregs.u.e.impl.fsl.mcar;
|
|
|
|
env->spr[SPR_HID0] = sregs.u.e.impl.fsl.hid0;
|
|
|
|
|
|
|
|
if (sregs.u.e.impl.fsl.features & KVM_SREGS_E_FSL_PIDn) {
|
|
|
|
env->spr[SPR_BOOKE_PID1] = sregs.u.e.impl.fsl.pid1;
|
|
|
|
env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
struct kvm_sregs sregs;
|
|
|
|
int ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_SREGS, &sregs);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-02-23 03:39:18 +03:00
|
|
|
if (!cpu->vhyp) {
|
2016-03-09 03:58:33 +03:00
|
|
|
ppc_store_sdr1(env, sregs.u.s.sdr1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sync SLB */
|
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
/*
|
|
|
|
* The packed SLB array we get from KVM_GET_SREGS only contains
|
|
|
|
* information about valid entries. So we flush our internal copy
|
|
|
|
* to get rid of stale ones, then put all valid SLB entries back
|
|
|
|
* in.
|
|
|
|
*/
|
|
|
|
memset(env->slb, 0, sizeof(env->slb));
|
|
|
|
for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
|
|
|
|
target_ulong rb = sregs.u.s.ppc64.slb[i].slbe;
|
|
|
|
target_ulong rs = sregs.u.s.ppc64.slb[i].slbv;
|
|
|
|
/*
|
|
|
|
* Only restore valid entries
|
|
|
|
*/
|
|
|
|
if (rb & SLB_ESID_V) {
|
|
|
|
ppc_store_slb(cpu, rb & 0xfff, rb & ~0xfffULL, rs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Sync SRs */
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
env->sr[i] = sregs.u.s.ppc32.sr[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sync BATs */
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
env->DBAT[0][i] = sregs.u.s.ppc32.dbat[i] & 0xffffffff;
|
|
|
|
env->DBAT[1][i] = sregs.u.s.ppc32.dbat[i] >> 32;
|
|
|
|
env->IBAT[0][i] = sregs.u.s.ppc32.ibat[i] & 0xffffffff;
|
|
|
|
env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
int kvm_arch_get_registers(CPUState *cs)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2012-10-31 09:57:49 +04:00
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
2008-12-16 13:43:58 +03:00
|
|
|
struct kvm_regs regs;
|
2010-11-25 10:20:46 +03:00
|
|
|
int i, ret;
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, ®s);
|
2019-03-21 13:47:25 +03:00
|
|
|
if (ret < 0) {
|
2008-12-16 13:43:58 +03:00
|
|
|
return ret;
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2023-05-03 12:36:18 +03:00
|
|
|
ppc_set_cr(env, regs.cr);
|
2008-12-16 13:43:58 +03:00
|
|
|
env->ctr = regs.ctr;
|
|
|
|
env->lr = regs.lr;
|
2013-02-20 11:52:13 +04:00
|
|
|
cpu_write_xer(env, regs.xer);
|
2008-12-16 13:43:58 +03:00
|
|
|
env->msr = regs.msr;
|
|
|
|
env->nip = regs.pc;
|
|
|
|
|
|
|
|
env->spr[SPR_SRR0] = regs.srr0;
|
|
|
|
env->spr[SPR_SRR1] = regs.srr1;
|
|
|
|
|
|
|
|
env->spr[SPR_SPRG0] = regs.sprg0;
|
|
|
|
env->spr[SPR_SPRG1] = regs.sprg1;
|
|
|
|
env->spr[SPR_SPRG2] = regs.sprg2;
|
|
|
|
env->spr[SPR_SPRG3] = regs.sprg3;
|
|
|
|
env->spr[SPR_SPRG4] = regs.sprg4;
|
|
|
|
env->spr[SPR_SPRG5] = regs.sprg5;
|
|
|
|
env->spr[SPR_SPRG6] = regs.sprg6;
|
|
|
|
env->spr[SPR_SPRG7] = regs.sprg7;
|
|
|
|
|
2011-04-30 02:10:23 +04:00
|
|
|
env->spr[SPR_BOOKE_PID] = regs.pid;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
for (i = 0; i < 32; i++) {
|
2008-12-16 13:43:58 +03:00
|
|
|
env->gpr[i] = regs.gpr[i];
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2013-02-20 20:41:51 +04:00
|
|
|
kvm_get_fp(cs);
|
|
|
|
|
2011-04-30 02:10:23 +04:00
|
|
|
if (cap_booke_sregs) {
|
2016-03-09 03:58:33 +03:00
|
|
|
ret = kvmppc_get_booke_sregs(cpu);
|
2011-04-30 02:10:23 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2011-05-25 17:04:42 +04:00
|
|
|
}
|
2011-04-30 02:10:23 +04:00
|
|
|
|
|
|
|
if (cap_segstate) {
|
2016-03-09 03:58:33 +03:00
|
|
|
ret = kvmppc_get_books_sregs(cpu);
|
2011-04-30 02:10:23 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
2011-05-25 17:04:42 +04:00
|
|
|
}
|
2009-12-03 01:19:47 +03:00
|
|
|
|
2013-02-20 20:41:50 +04:00
|
|
|
if (cap_hior) {
|
|
|
|
kvm_get_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap_one_reg) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* We deliberately ignore errors here, for kernels which have
|
2013-02-20 20:41:50 +04:00
|
|
|
* the ONE_REG calls, but don't support the specific
|
|
|
|
* registers, there's a reasonable chance things will still
|
2019-03-21 13:47:25 +03:00
|
|
|
* work, at least until we try to migrate.
|
|
|
|
*/
|
2013-02-20 20:41:50 +04:00
|
|
|
for (i = 0; i < 1024; i++) {
|
|
|
|
uint64_t id = env->spr_cb[i].one_reg_id;
|
|
|
|
|
|
|
|
if (id != 0) {
|
|
|
|
kvm_get_one_spr(cs, id, i);
|
|
|
|
}
|
|
|
|
}
|
2013-04-07 23:08:22 +04:00
|
|
|
|
|
|
|
#ifdef TARGET_PPC64
|
2022-05-05 00:05:37 +03:00
|
|
|
if (FIELD_EX64(env->msr, MSR, TS)) {
|
2014-06-04 16:51:00 +04:00
|
|
|
for (i = 0; i < ARRAY_SIZE(env->tm_gpr); i++) {
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_GPR(i), &env->tm_gpr[i]);
|
|
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(env->tm_vsr); i++) {
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSR(i), &env->tm_vsr[i]);
|
|
|
|
}
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_CR, &env->tm_cr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_LR, &env->tm_lr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_CTR, &env->tm_ctr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_FPSCR, &env->tm_fpscr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_AMR, &env->tm_amr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_PPR, &env->tm_ppr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VRSAVE, &env->tm_vrsave);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_VSCR, &env->tm_vscr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_DSCR, &env->tm_dscr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TM_TAR, &env->tm_tar);
|
|
|
|
}
|
|
|
|
|
2013-04-07 23:08:22 +04:00
|
|
|
if (cap_papr) {
|
|
|
|
if (kvm_get_vpa(cs) < 0) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_failed_get_vpa();
|
2013-04-07 23:08:22 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-01 14:37:09 +04:00
|
|
|
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
|
2019-09-23 11:41:10 +03:00
|
|
|
kvm_get_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
|
2013-04-07 23:08:22 +04:00
|
|
|
#endif
|
2013-02-20 20:41:50 +04:00
|
|
|
}
|
|
|
|
|
2008-12-16 13:43:58 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
|
2010-08-30 15:49:15 +04:00
|
|
|
{
|
|
|
|
unsigned virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
|
|
|
|
|
|
|
|
if (irq != PPC_INTERRUPT_EXT) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-21 10:37:34 +03:00
|
|
|
if (!cap_interrupt_unset) {
|
2010-08-30 15:49:15 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
|
2010-08-30 15:49:15 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2019-07-25 17:15:08 +03:00
|
|
|
return;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2015-04-08 14:30:58 +03:00
|
|
|
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2015-04-08 14:30:58 +03:00
|
|
|
return MEMTXATTRS_UNSPECIFIED;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
int kvm_arch_process_async_events(CPUState *cs)
|
2010-05-04 16:45:27 +04:00
|
|
|
{
|
2013-01-17 21:51:17 +04:00
|
|
|
return cs->halted;
|
2010-05-04 16:45:27 +04:00
|
|
|
}
|
|
|
|
|
2013-01-17 21:51:17 +04:00
|
|
|
static int kvmppc_handle_halt(PowerPCCPU *cpu)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2013-01-17 21:51:17 +04:00
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
|
2022-05-05 00:05:26 +03:00
|
|
|
if (!(cs->interrupt_request & CPU_INTERRUPT_HARD) &&
|
|
|
|
FIELD_EX64(env->msr, MSR, EE)) {
|
2013-01-17 21:51:17 +04:00
|
|
|
cs->halted = 1;
|
2013-08-26 10:31:06 +04:00
|
|
|
cs->exception_index = EXCP_HLT;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2011-03-15 14:26:28 +03:00
|
|
|
return 0;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* map dcr access to existing qemu dcr emulation */
|
2019-03-21 13:47:25 +03:00
|
|
|
static int kvmppc_handle_dcr_read(CPUPPCState *env,
|
|
|
|
uint32_t dcrn, uint32_t *data)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2019-03-21 13:47:25 +03:00
|
|
|
if (ppc_dcr_read(env->dcr_env, dcrn, data) < 0) {
|
2008-12-16 13:43:58 +03:00
|
|
|
fprintf(stderr, "Read to unhandled DCR (0x%x)\n", dcrn);
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2011-03-15 14:26:28 +03:00
|
|
|
return 0;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
static int kvmppc_handle_dcr_write(CPUPPCState *env,
|
|
|
|
uint32_t dcrn, uint32_t data)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2019-03-21 13:47:25 +03:00
|
|
|
if (ppc_dcr_write(env->dcr_env, dcrn, data) < 0) {
|
2008-12-16 13:43:58 +03:00
|
|
|
fprintf(stderr, "Write to unhandled DCR (0x%x)\n", dcrn);
|
2019-03-21 13:47:25 +03:00
|
|
|
}
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2011-03-15 14:26:28 +03:00
|
|
|
return 0;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:38 +04:00
|
|
|
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
|
|
|
{
|
|
|
|
/* Mixed endian case is not handled */
|
|
|
|
uint32_t sc = debug_inst_opcode;
|
|
|
|
|
|
|
|
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
|
|
|
|
sizeof(sc), 0) ||
|
|
|
|
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 1)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
|
|
|
{
|
|
|
|
uint32_t sc;
|
|
|
|
|
|
|
|
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&sc, sizeof(sc), 0) ||
|
|
|
|
sc != debug_inst_opcode ||
|
|
|
|
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn,
|
|
|
|
sizeof(sc), 1)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:37 +04:00
|
|
|
static int find_hw_breakpoint(target_ulong addr, int type)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
assert((nb_hw_breakpoint + nb_hw_watchpoint)
|
|
|
|
<= ARRAY_SIZE(hw_debug_points));
|
|
|
|
|
|
|
|
for (n = 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) {
|
|
|
|
if (hw_debug_points[n].addr == addr &&
|
|
|
|
hw_debug_points[n].type == type) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int find_hw_watchpoint(target_ulong addr, int *flag)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = find_hw_breakpoint(addr, GDB_WATCHPOINT_ACCESS);
|
|
|
|
if (n >= 0) {
|
|
|
|
*flag = BP_MEM_ACCESS;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = find_hw_breakpoint(addr, GDB_WATCHPOINT_WRITE);
|
|
|
|
if (n >= 0) {
|
|
|
|
*flag = BP_MEM_WRITE;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = find_hw_breakpoint(addr, GDB_WATCHPOINT_READ);
|
|
|
|
if (n >= 0) {
|
|
|
|
*flag = BP_MEM_READ;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-08-07 18:57:00 +03:00
|
|
|
int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
|
2014-07-14 13:15:37 +04:00
|
|
|
{
|
2023-08-07 18:57:00 +03:00
|
|
|
const unsigned breakpoint_index = nb_hw_breakpoint + nb_hw_watchpoint;
|
|
|
|
if (breakpoint_index >= ARRAY_SIZE(hw_debug_points)) {
|
2014-07-14 13:15:37 +04:00
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2023-08-07 18:57:00 +03:00
|
|
|
hw_debug_points[breakpoint_index].addr = addr;
|
|
|
|
hw_debug_points[breakpoint_index].type = type;
|
2014-07-14 13:15:37 +04:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case GDB_BREAKPOINT_HW:
|
|
|
|
if (nb_hw_breakpoint >= max_hw_breakpoint) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (find_hw_breakpoint(addr, type) >= 0) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb_hw_breakpoint++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDB_WATCHPOINT_WRITE:
|
|
|
|
case GDB_WATCHPOINT_READ:
|
|
|
|
case GDB_WATCHPOINT_ACCESS:
|
|
|
|
if (nb_hw_watchpoint >= max_hw_watchpoint) {
|
|
|
|
return -ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (find_hw_breakpoint(addr, type) >= 0) {
|
|
|
|
return -EEXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb_hw_watchpoint++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-08-07 18:57:00 +03:00
|
|
|
int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
|
2014-07-14 13:15:37 +04:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
n = find_hw_breakpoint(addr, type);
|
|
|
|
if (n < 0) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case GDB_BREAKPOINT_HW:
|
|
|
|
nb_hw_breakpoint--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GDB_WATCHPOINT_WRITE:
|
|
|
|
case GDB_WATCHPOINT_READ:
|
|
|
|
case GDB_WATCHPOINT_ACCESS:
|
|
|
|
nb_hw_watchpoint--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
hw_debug_points[n] = hw_debug_points[nb_hw_breakpoint + nb_hw_watchpoint];
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void kvm_arch_remove_all_hw_breakpoints(void)
|
|
|
|
{
|
|
|
|
nb_hw_breakpoint = nb_hw_watchpoint = 0;
|
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:38 +04:00
|
|
|
void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
|
|
|
|
{
|
2014-07-14 13:15:37 +04:00
|
|
|
int n;
|
|
|
|
|
2014-07-14 13:15:38 +04:00
|
|
|
/* Software Breakpoint updates */
|
|
|
|
if (kvm_sw_breakpoints_active(cs)) {
|
|
|
|
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
|
|
|
|
}
|
2014-07-14 13:15:37 +04:00
|
|
|
|
|
|
|
assert((nb_hw_breakpoint + nb_hw_watchpoint)
|
|
|
|
<= ARRAY_SIZE(hw_debug_points));
|
|
|
|
assert((nb_hw_breakpoint + nb_hw_watchpoint) <= ARRAY_SIZE(dbg->arch.bp));
|
|
|
|
|
|
|
|
if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
|
|
|
|
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
|
|
|
|
memset(dbg->arch.bp, 0, sizeof(dbg->arch.bp));
|
|
|
|
for (n = 0; n < nb_hw_breakpoint + nb_hw_watchpoint; n++) {
|
|
|
|
switch (hw_debug_points[n].type) {
|
|
|
|
case GDB_BREAKPOINT_HW:
|
|
|
|
dbg->arch.bp[n].type = KVMPPC_DEBUG_BREAKPOINT;
|
|
|
|
break;
|
|
|
|
case GDB_WATCHPOINT_WRITE:
|
|
|
|
dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_WRITE;
|
|
|
|
break;
|
|
|
|
case GDB_WATCHPOINT_READ:
|
|
|
|
dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_READ;
|
|
|
|
break;
|
|
|
|
case GDB_WATCHPOINT_ACCESS:
|
|
|
|
dbg->arch.bp[n].type = KVMPPC_DEBUG_WATCH_WRITE |
|
|
|
|
KVMPPC_DEBUG_WATCH_READ;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cpu_abort(cs, "Unsupported breakpoint type\n");
|
|
|
|
}
|
|
|
|
dbg->arch.bp[n].addr = hw_debug_points[n].addr;
|
|
|
|
}
|
|
|
|
}
|
2014-07-14 13:15:38 +04:00
|
|
|
}
|
|
|
|
|
2019-03-01 01:57:57 +03:00
|
|
|
static int kvm_handle_hw_breakpoint(CPUState *cs,
|
|
|
|
struct kvm_debug_exit_arch *arch_info)
|
|
|
|
{
|
2020-01-10 18:13:42 +03:00
|
|
|
int handle = DEBUG_RETURN_GUEST;
|
2019-03-01 01:57:57 +03:00
|
|
|
int n;
|
|
|
|
int flag = 0;
|
|
|
|
|
|
|
|
if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
|
|
|
|
if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
|
|
|
|
n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
|
|
|
|
if (n >= 0) {
|
2020-01-10 18:13:42 +03:00
|
|
|
handle = DEBUG_RETURN_GDB;
|
2019-03-01 01:57:57 +03:00
|
|
|
}
|
|
|
|
} else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
|
|
|
|
KVMPPC_DEBUG_WATCH_WRITE)) {
|
|
|
|
n = find_hw_watchpoint(arch_info->address, &flag);
|
|
|
|
if (n >= 0) {
|
2020-01-10 18:13:42 +03:00
|
|
|
handle = DEBUG_RETURN_GDB;
|
2019-03-01 01:57:57 +03:00
|
|
|
cs->watchpoint_hit = &hw_watchpoint;
|
|
|
|
hw_watchpoint.vaddr = hw_debug_points[n].addr;
|
|
|
|
hw_watchpoint.flags = flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
2019-03-01 01:57:58 +03:00
|
|
|
static int kvm_handle_singlestep(void)
|
|
|
|
{
|
2020-01-10 18:13:42 +03:00
|
|
|
return DEBUG_RETURN_GDB;
|
2019-03-01 01:57:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int kvm_handle_sw_breakpoint(void)
|
|
|
|
{
|
2020-01-10 18:13:42 +03:00
|
|
|
return DEBUG_RETURN_GDB;
|
2019-03-01 01:57:58 +03:00
|
|
|
}
|
|
|
|
|
2014-07-14 13:15:38 +04:00
|
|
|
static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
|
|
|
|
|
2014-07-14 13:15:37 +04:00
|
|
|
if (cs->singlestep_enabled) {
|
2019-03-01 01:57:58 +03:00
|
|
|
return kvm_handle_singlestep();
|
|
|
|
}
|
2014-07-14 13:15:38 +04:00
|
|
|
|
2019-03-01 01:57:58 +03:00
|
|
|
if (arch_info->status) {
|
|
|
|
return kvm_handle_hw_breakpoint(cs, arch_info);
|
2014-07-14 13:15:38 +04:00
|
|
|
}
|
|
|
|
|
2019-03-01 01:57:58 +03:00
|
|
|
if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
|
|
|
|
return kvm_handle_sw_breakpoint();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* QEMU is not able to handle debug exception, so inject
|
|
|
|
* program exception to guest;
|
|
|
|
* Yes program exception NOT debug exception !!
|
|
|
|
* When QEMU is using debug resources then debug exception must
|
|
|
|
* be always set. To achieve this we set MSR_DE and also set
|
|
|
|
* MSRP_DEP so guest cannot change MSR_DE.
|
|
|
|
* When emulating debug resource for guest we want guest
|
|
|
|
* to control MSR_DE (enable/disable debug interrupt on need).
|
|
|
|
* Supporting both configurations are NOT possible.
|
|
|
|
* So the result is that we cannot share debug resources
|
|
|
|
* between QEMU and Guest on BOOKE architecture.
|
|
|
|
* In the current design QEMU gets the priority over guest,
|
|
|
|
* this means that if QEMU is using debug resources then guest
|
|
|
|
* cannot use them;
|
|
|
|
* For software breakpoint QEMU uses a privileged instruction;
|
|
|
|
* So there cannot be any reason that we are here for guest
|
|
|
|
* set debug exception, only possibility is guest executed a
|
|
|
|
* privileged / illegal instruction and that's why we are
|
|
|
|
* injecting a program interrupt.
|
|
|
|
*/
|
|
|
|
cpu_synchronize_state(cs);
|
|
|
|
/*
|
|
|
|
* env->nip is PC, so increment this by 4 to use
|
|
|
|
* ppc_cpu_do_interrupt(), which set srr0 = env->nip - 4.
|
|
|
|
*/
|
|
|
|
env->nip += 4;
|
|
|
|
cs->exception_index = POWERPC_EXCP_PROGRAM;
|
|
|
|
env->error_code = POWERPC_EXCP_INVAL;
|
|
|
|
ppc_cpu_do_interrupt(cs);
|
|
|
|
|
2020-01-10 18:13:42 +03:00
|
|
|
return DEBUG_RETURN_GUEST;
|
2014-07-14 13:15:38 +04:00
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
2008-12-16 13:43:58 +03:00
|
|
|
{
|
2012-10-31 09:57:49 +04:00
|
|
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
2011-03-15 14:26:28 +03:00
|
|
|
int ret;
|
2008-12-16 13:43:58 +03:00
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_lock();
|
2015-06-18 19:47:23 +03:00
|
|
|
|
2008-12-16 13:43:58 +03:00
|
|
|
switch (run->exit_reason) {
|
|
|
|
case KVM_EXIT_DCR:
|
|
|
|
if (run->dcr.is_write) {
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_handle_dcr_write();
|
2008-12-16 13:43:58 +03:00
|
|
|
ret = kvmppc_handle_dcr_write(env, run->dcr.dcrn, run->dcr.data);
|
|
|
|
} else {
|
2019-04-30 20:28:42 +03:00
|
|
|
trace_kvm_handle_dcr_read();
|
2008-12-16 13:43:58 +03:00
|
|
|
ret = kvmppc_handle_dcr_read(env, run->dcr.dcrn, &run->dcr.data);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KVM_EXIT_HLT:
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_handle_halt();
|
2013-01-17 21:51:17 +04:00
|
|
|
ret = kvmppc_handle_halt(cpu);
|
2008-12-16 13:43:58 +03:00
|
|
|
break;
|
target-ppc: Remove CONFIG_PSERIES dependency in kvm.c
target-ppc/kvm.c has an #ifdef on CONFIG_PSERIES, for the handling of
KVM exits due to a PAPR hypercall from the guest. However, since commit
e4c8b28cde12d01ada8fe869567dc5717a2dfcb7 "ppc: express FDT dependency of
pSeries and e500 boards via default-configs/", this hasn't worked properly.
That patch altered the configuration setup so that although CONFIG_PSERIES
is visible from the Makefiles, it is not visible from C files. This broke
the pseries machine when KVM is in use.
This patch makes a quick and dirty fix, by removing the CONFIG_PSERIES
dependency, replacing it with TARGET_PPC64 (since removing it entirely
leads to type mismatch errors). Technically this breaks the build when
configured with --disable-fdt, since that disables CONFIG_PSERIES on
TARGET_PPC64. However, it turns out the build was already broken in that
case, so this fixes pseries kvm without breaking anything extra. I'm
looking into how to fix that build breakage, but I don't think that need
delay applying this patch.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2013-03-13 19:53:27 +04:00
|
|
|
#if defined(TARGET_PPC64)
|
2011-08-09 19:57:37 +04:00
|
|
|
case KVM_EXIT_PAPR_HCALL:
|
2022-03-26 01:33:16 +03:00
|
|
|
trace_kvm_handle_papr_hcall(run->papr_hcall.nr);
|
2012-10-31 09:57:49 +04:00
|
|
|
run->papr_hcall.ret = spapr_hypercall(cpu,
|
2012-05-03 08:13:14 +04:00
|
|
|
run->papr_hcall.nr,
|
2011-08-09 19:57:37 +04:00
|
|
|
run->papr_hcall.args);
|
2012-08-06 22:44:45 +04:00
|
|
|
ret = 0;
|
2011-08-09 19:57:37 +04:00
|
|
|
break;
|
|
|
|
#endif
|
2013-01-17 14:54:38 +04:00
|
|
|
case KVM_EXIT_EPR:
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_handle_epr();
|
2014-02-14 12:15:21 +04:00
|
|
|
run->epr.epr = ldl_phys(cs->as, env->mpic_iack);
|
2013-01-17 14:54:38 +04:00
|
|
|
ret = 0;
|
|
|
|
break;
|
2013-02-24 22:16:21 +04:00
|
|
|
case KVM_EXIT_WATCHDOG:
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_handle_watchdog_expiry();
|
2013-02-24 22:16:21 +04:00
|
|
|
watchdog_perform_action();
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2014-07-14 13:15:38 +04:00
|
|
|
case KVM_EXIT_DEBUG:
|
2019-04-05 11:05:24 +03:00
|
|
|
trace_kvm_handle_debug_exception();
|
2014-07-14 13:15:38 +04:00
|
|
|
if (kvm_handle_debug(cpu, run)) {
|
|
|
|
ret = EXCP_DEBUG;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* re-enter, this exception was guest-internal */
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
|
2020-01-30 21:44:19 +03:00
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
case KVM_EXIT_NMI:
|
|
|
|
trace_kvm_handle_nmi_exception();
|
|
|
|
ret = kvm_handle_nmi(cpu, run);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2011-01-21 23:48:06 +03:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
|
|
|
|
ret = -1;
|
|
|
|
break;
|
2008-12-16 13:43:58 +03:00
|
|
|
}
|
|
|
|
|
2024-01-02 18:35:25 +03:00
|
|
|
bql_unlock();
|
2008-12-16 13:43:58 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-02-24 22:16:21 +04:00
|
|
|
int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
uint32_t bits = tsr_bits;
|
|
|
|
struct kvm_one_reg reg = {
|
|
|
|
.id = KVM_REG_PPC_OR_TSR,
|
|
|
|
.addr = (uintptr_t) &bits,
|
|
|
|
};
|
|
|
|
|
2023-06-20 08:59:11 +03:00
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-24 22:16:21 +04:00
|
|
|
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
|
|
|
|
{
|
|
|
|
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
uint32_t bits = tsr_bits;
|
|
|
|
struct kvm_one_reg reg = {
|
|
|
|
.id = KVM_REG_PPC_CLEAR_TSR,
|
|
|
|
.addr = (uintptr_t) &bits,
|
|
|
|
};
|
|
|
|
|
2023-06-20 08:59:11 +03:00
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-24 22:16:21 +04:00
|
|
|
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_set_tcr(PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
CPUPPCState *env = &cpu->env;
|
|
|
|
uint32_t tcr = env->spr[SPR_BOOKE_TCR];
|
|
|
|
|
|
|
|
struct kvm_one_reg reg = {
|
|
|
|
.id = KVM_REG_PPC_TCR,
|
|
|
|
.addr = (uintptr_t) &tcr,
|
|
|
|
};
|
|
|
|
|
2023-06-20 08:59:11 +03:00
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-24 22:16:21 +04:00
|
|
|
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cap_ppc_watchdog) {
|
|
|
|
printf("warning: KVM does not support watchdog");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-04-09 19:21:57 +04:00
|
|
|
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_BOOKE_WATCHDOG, 0);
|
2013-02-24 22:16:21 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
|
|
|
|
__func__, strerror(-ret));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-09 19:37:05 +03:00
|
|
|
static int read_cpuinfo(const char *field, char *value, int len)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int ret = -1;
|
|
|
|
int field_len = strlen(field);
|
|
|
|
char line[512];
|
|
|
|
|
|
|
|
f = fopen("/proc/cpuinfo", "r");
|
|
|
|
if (!f) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2014-07-09 14:38:37 +04:00
|
|
|
if (!fgets(line, sizeof(line), f)) {
|
2010-02-09 19:37:05 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!strncmp(line, field, field_len)) {
|
2012-10-04 15:09:52 +04:00
|
|
|
pstrcpy(value, len, line);
|
2010-02-09 19:37:05 +03:00
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
2019-03-21 13:47:25 +03:00
|
|
|
} while (*line);
|
2010-02-09 19:37:05 +03:00
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-03-17 20:57:07 +03:00
|
|
|
static uint32_t kvmppc_get_tbfreq_procfs(void)
|
2010-02-09 19:37:05 +03:00
|
|
|
{
|
|
|
|
char line[512];
|
|
|
|
char *ns;
|
2021-03-17 20:57:07 +03:00
|
|
|
uint32_t tbfreq_fallback = NANOSECONDS_PER_SECOND;
|
|
|
|
uint32_t tbfreq_procfs;
|
2010-02-09 19:37:05 +03:00
|
|
|
|
|
|
|
if (read_cpuinfo("timebase", line, sizeof(line))) {
|
2021-03-17 20:57:07 +03:00
|
|
|
return tbfreq_fallback;
|
2010-02-09 19:37:05 +03:00
|
|
|
}
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
ns = strchr(line, ':');
|
|
|
|
if (!ns) {
|
2021-03-17 20:57:07 +03:00
|
|
|
return tbfreq_fallback;
|
2010-02-09 19:37:05 +03:00
|
|
|
}
|
|
|
|
|
2021-03-17 20:57:07 +03:00
|
|
|
tbfreq_procfs = atoi(++ns);
|
|
|
|
|
|
|
|
/* 0 is certainly not acceptable by the guest, return fallback value */
|
|
|
|
return tbfreq_procfs ? tbfreq_procfs : tbfreq_fallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t kvmppc_get_tbfreq(void)
|
|
|
|
{
|
|
|
|
static uint32_t cached_tbfreq;
|
|
|
|
|
|
|
|
if (!cached_tbfreq) {
|
|
|
|
cached_tbfreq = kvmppc_get_tbfreq_procfs();
|
|
|
|
}
|
2010-02-09 19:37:05 +03:00
|
|
|
|
2021-03-17 20:57:07 +03:00
|
|
|
return cached_tbfreq;
|
2010-02-09 19:37:05 +03:00
|
|
|
}
|
2010-05-10 12:21:34 +04:00
|
|
|
|
2014-07-09 14:38:37 +04:00
|
|
|
bool kvmppc_get_host_serial(char **value)
|
|
|
|
{
|
|
|
|
return g_file_get_contents("/proc/device-tree/system-id", value, NULL,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool kvmppc_get_host_model(char **value)
|
|
|
|
{
|
|
|
|
return g_file_get_contents("/proc/device-tree/model", value, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2011-07-21 04:29:15 +04:00
|
|
|
/* Try to find a device tree node for a CPU with clock-frequency property */
|
|
|
|
static int kvmppc_find_cpu_dt(char *buf, int buf_len)
|
|
|
|
{
|
|
|
|
struct dirent *dirp;
|
|
|
|
DIR *dp;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
dp = opendir(PROC_DEVTREE_CPU);
|
|
|
|
if (!dp) {
|
2011-07-21 04:29:15 +04:00
|
|
|
printf("Can't open directory " PROC_DEVTREE_CPU "\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
while ((dirp = readdir(dp)) != NULL) {
|
|
|
|
FILE *f;
|
2022-07-13 00:08:10 +03:00
|
|
|
|
|
|
|
/* Don't accidentally read from the current and parent directories */
|
|
|
|
if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-07-21 04:29:15 +04:00
|
|
|
snprintf(buf, buf_len, "%s%s/clock-frequency", PROC_DEVTREE_CPU,
|
|
|
|
dirp->d_name);
|
|
|
|
f = fopen(buf, "r");
|
|
|
|
if (f) {
|
|
|
|
snprintf(buf, buf_len, "%s%s", PROC_DEVTREE_CPU, dirp->d_name);
|
|
|
|
fclose(f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
buf[0] = '\0';
|
|
|
|
}
|
|
|
|
closedir(dp);
|
|
|
|
if (buf[0] == '\0') {
|
|
|
|
printf("Unknown host!\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-14 05:13:07 +03:00
|
|
|
static uint64_t kvmppc_read_int_dt(const char *filename)
|
2011-07-21 04:29:15 +04:00
|
|
|
{
|
2011-10-10 22:31:00 +04:00
|
|
|
union {
|
|
|
|
uint32_t v32;
|
|
|
|
uint64_t v64;
|
|
|
|
} u;
|
2011-07-21 04:29:15 +04:00
|
|
|
FILE *f;
|
|
|
|
int len;
|
|
|
|
|
2015-11-14 05:13:07 +03:00
|
|
|
f = fopen(filename, "rb");
|
2011-07-21 04:29:15 +04:00
|
|
|
if (!f) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-10-10 22:31:00 +04:00
|
|
|
len = fread(&u, 1, sizeof(u), f);
|
2011-07-21 04:29:15 +04:00
|
|
|
fclose(f);
|
|
|
|
switch (len) {
|
2011-10-10 22:31:00 +04:00
|
|
|
case 4:
|
|
|
|
/* property is a 32-bit quantity */
|
|
|
|
return be32_to_cpu(u.v32);
|
|
|
|
case 8:
|
|
|
|
return be64_to_cpu(u.v64);
|
2011-07-21 04:29:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Read a CPU node property from the host device tree that's a single
|
2015-11-14 05:13:07 +03:00
|
|
|
* integer (32-bit or 64-bit). Returns 0 if anything goes wrong
|
2019-03-21 13:47:25 +03:00
|
|
|
* (can't find or open the property, or doesn't understand the format)
|
|
|
|
*/
|
2015-11-14 05:13:07 +03:00
|
|
|
static uint64_t kvmppc_read_int_cpu_dt(const char *propname)
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX], *tmp;
|
|
|
|
uint64_t val;
|
|
|
|
|
|
|
|
if (kvmppc_find_cpu_dt(buf, sizeof(buf))) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = g_strdup_printf("%s/%s", buf, propname);
|
|
|
|
val = kvmppc_read_int_dt(tmp);
|
|
|
|
g_free(tmp);
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
2011-10-10 22:31:00 +04:00
|
|
|
uint64_t kvmppc_get_clockfreq(void)
|
|
|
|
{
|
|
|
|
return kvmppc_read_int_cpu_dt("clock-frequency");
|
|
|
|
}
|
|
|
|
|
2019-03-01 05:43:16 +03:00
|
|
|
static int kvmppc_get_dec_bits(void)
|
|
|
|
{
|
|
|
|
int nr_bits = kvmppc_read_int_cpu_dt("ibm,dec-bits");
|
|
|
|
|
|
|
|
if (nr_bits > 0) {
|
|
|
|
return nr_bits;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-03 16:37:02 +04:00
|
|
|
static int kvmppc_get_pvinfo(CPUPPCState *env, struct kvm_ppc_pvinfo *pvinfo)
|
2019-03-23 05:07:57 +03:00
|
|
|
{
|
|
|
|
CPUState *cs = env_cpu(env);
|
2013-01-03 16:37:02 +04:00
|
|
|
|
2014-07-14 21:17:35 +04:00
|
|
|
if (kvm_vm_check_extension(cs->kvm_state, KVM_CAP_PPC_GET_PVINFO) &&
|
2013-01-03 16:37:02 +04:00
|
|
|
!kvm_vm_ioctl(cs->kvm_state, KVM_PPC_GET_PVINFO, pvinfo)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_get_hasidle(CPUPPCState *env)
|
|
|
|
{
|
|
|
|
struct kvm_ppc_pvinfo pvinfo;
|
|
|
|
|
|
|
|
if (!kvmppc_get_pvinfo(env, &pvinfo) &&
|
|
|
|
(pvinfo.flags & KVM_PPC_PVINFO_FLAGS_EV_IDLE)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-03-14 04:38:22 +04:00
|
|
|
int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
|
2010-08-03 17:22:42 +04:00
|
|
|
{
|
2019-03-21 13:47:25 +03:00
|
|
|
uint32_t *hc = (uint32_t *)buf;
|
2010-08-03 17:22:42 +04:00
|
|
|
struct kvm_ppc_pvinfo pvinfo;
|
|
|
|
|
2013-01-03 16:37:02 +04:00
|
|
|
if (!kvmppc_get_pvinfo(env, &pvinfo)) {
|
2010-08-03 17:22:42 +04:00
|
|
|
memcpy(buf, pvinfo.hcall, buf_len);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-06-11 14:19:03 +04:00
|
|
|
* Fallback to always fail hypercalls regardless of endianness:
|
2010-08-03 17:22:42 +04:00
|
|
|
*
|
2014-06-11 14:19:03 +04:00
|
|
|
* tdi 0,r0,72 (becomes b .+8 in wrong endian, nop in good endian)
|
2010-08-03 17:22:42 +04:00
|
|
|
* li r3, -1
|
2014-06-11 14:19:03 +04:00
|
|
|
* b .+8 (becomes nop in wrong endian)
|
|
|
|
* bswap32(li r3, -1)
|
2010-08-03 17:22:42 +04:00
|
|
|
*/
|
|
|
|
|
2014-06-11 14:19:03 +04:00
|
|
|
hc[0] = cpu_to_be32(0x08000048);
|
|
|
|
hc[1] = cpu_to_be32(0x3860ffff);
|
|
|
|
hc[2] = cpu_to_be32(0x48000008);
|
|
|
|
hc[3] = cpu_to_be32(bswap32(0x3860ffff));
|
2010-08-03 17:22:42 +04:00
|
|
|
|
2016-03-21 05:14:02 +03:00
|
|
|
return 1;
|
2010-08-03 17:22:42 +04:00
|
|
|
}
|
|
|
|
|
2015-05-07 08:33:59 +03:00
|
|
|
static inline int kvmppc_enable_hcall(KVMState *s, target_ulong hcall)
|
|
|
|
{
|
|
|
|
return kvm_vm_enable_cap(s, KVM_CAP_PPC_ENABLE_HCALL, 0, hcall, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kvmppc_enable_logical_ci_hcalls(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* FIXME: it would be nice if we could detect the cases where
|
|
|
|
* we're using a device which requires the in kernel
|
|
|
|
* implementation of these hcalls, but the kernel lacks them and
|
|
|
|
* produce a warning.
|
|
|
|
*/
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_LOGICAL_CI_LOAD);
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_LOGICAL_CI_STORE);
|
|
|
|
}
|
|
|
|
|
2015-09-08 04:25:13 +03:00
|
|
|
void kvmppc_enable_set_mode_hcall(void)
|
|
|
|
{
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_SET_MODE);
|
|
|
|
}
|
|
|
|
|
2016-08-30 04:02:47 +03:00
|
|
|
void kvmppc_enable_clear_ref_mod_hcalls(void)
|
|
|
|
{
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_CLEAR_REF);
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_CLEAR_MOD);
|
|
|
|
}
|
|
|
|
|
2019-03-06 09:06:08 +03:00
|
|
|
void kvmppc_enable_h_page_init(void)
|
|
|
|
{
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_PAGE_INIT);
|
|
|
|
}
|
|
|
|
|
2021-07-06 14:24:40 +03:00
|
|
|
void kvmppc_enable_h_rpt_invalidate(void)
|
|
|
|
{
|
|
|
|
kvmppc_enable_hcall(kvm_state, H_RPT_INVALIDATE);
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:06:49 +04:00
|
|
|
void kvmppc_set_papr(PowerPCCPU *cpu)
|
2011-08-09 19:57:37 +04:00
|
|
|
{
|
2012-10-31 09:06:49 +04:00
|
|
|
CPUState *cs = CPU(cpu);
|
2011-08-09 19:57:37 +04:00
|
|
|
int ret;
|
|
|
|
|
2018-04-05 09:02:51 +03:00
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-04-09 19:21:57 +04:00
|
|
|
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0);
|
2011-08-09 19:57:37 +04:00
|
|
|
if (ret) {
|
2016-02-19 00:01:38 +03:00
|
|
|
error_report("This vCPU type or KVM version does not support PAPR");
|
|
|
|
exit(1);
|
2011-09-14 23:38:45 +04:00
|
|
|
}
|
2013-04-07 23:08:22 +04:00
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Update the capability flag so we sync the right information
|
|
|
|
* with kvm
|
|
|
|
*/
|
2013-04-07 23:08:22 +04:00
|
|
|
cap_papr = 1;
|
2011-08-09 19:57:37 +04:00
|
|
|
}
|
|
|
|
|
2016-10-28 14:09:37 +03:00
|
|
|
int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
|
2014-05-23 06:26:58 +04:00
|
|
|
{
|
2016-10-28 14:09:37 +03:00
|
|
|
return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &compat_pvr);
|
2014-05-23 06:26:58 +04:00
|
|
|
}
|
|
|
|
|
2013-01-17 14:54:38 +04:00
|
|
|
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
int ret;
|
|
|
|
|
2014-04-09 19:21:57 +04:00
|
|
|
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_EPR, 0, mpic_proxy);
|
2013-01-17 14:54:38 +04:00
|
|
|
if (ret && mpic_proxy) {
|
2016-02-19 00:01:38 +03:00
|
|
|
error_report("This KVM version does not support EPR");
|
|
|
|
exit(1);
|
2013-01-17 14:54:38 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-25 17:29:03 +03:00
|
|
|
bool kvmppc_get_fwnmi(void)
|
|
|
|
{
|
|
|
|
return cap_fwnmi;
|
|
|
|
}
|
|
|
|
|
2020-07-24 11:35:33 +03:00
|
|
|
int kvmppc_set_fwnmi(PowerPCCPU *cpu)
|
2020-01-30 21:44:18 +03:00
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
return kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_FWNMI, 0);
|
|
|
|
}
|
|
|
|
|
2011-09-30 01:39:10 +04:00
|
|
|
int kvmppc_smt_threads(void)
|
|
|
|
{
|
|
|
|
return cap_ppc_smt ? cap_ppc_smt : 1;
|
|
|
|
}
|
|
|
|
|
2017-08-18 08:50:22 +03:00
|
|
|
int kvmppc_set_smt_threads(int smt)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_SMT, 0, smt, 0);
|
|
|
|
if (!ret) {
|
|
|
|
cap_ppc_smt = smt;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-12-05 20:46:21 +03:00
|
|
|
void kvmppc_error_append_smt_possible_hint(Error *const *errp)
|
2017-08-18 08:50:22 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
GString *g;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
assert(kvm_enabled());
|
|
|
|
if (cap_ppc_smt_possible) {
|
|
|
|
g = g_string_new("Available VSMT modes:");
|
|
|
|
for (i = 63; i >= 0; i--) {
|
|
|
|
if ((1UL << i) & cap_ppc_smt_possible) {
|
|
|
|
g_string_append_printf(g, " %lu", (1UL << i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s = g_string_free(g, false);
|
2019-12-18 10:36:27 +03:00
|
|
|
error_append_hint(errp, "%s.\n", s);
|
2017-08-18 08:50:22 +03:00
|
|
|
g_free(s);
|
|
|
|
} else {
|
2019-12-18 10:36:27 +03:00
|
|
|
error_append_hint(errp,
|
2017-08-18 08:50:22 +03:00
|
|
|
"This KVM seems to be too old to support VSMT.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-12 20:57:12 +04:00
|
|
|
#ifdef TARGET_PPC64
|
2019-11-28 08:12:06 +03:00
|
|
|
uint64_t kvmppc_vrma_limit(unsigned int hash_shift)
|
2012-09-12 20:57:12 +04:00
|
|
|
{
|
2013-04-07 23:08:18 +04:00
|
|
|
struct kvm_ppc_smmu_info info;
|
|
|
|
long rampagesize, best_page_shift;
|
|
|
|
int i;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Find the largest hardware supported page size that's less than
|
|
|
|
* or equal to the (logical) backing page size of guest RAM
|
|
|
|
*/
|
2018-06-29 12:48:32 +03:00
|
|
|
kvm_get_smmu_info(&info, &error_fatal);
|
2019-04-17 14:31:43 +03:00
|
|
|
rampagesize = qemu_minrampagesize();
|
2013-04-07 23:08:18 +04:00
|
|
|
best_page_shift = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
|
|
|
|
struct kvm_ppc_one_seg_page_size *sps = &info.sps[i];
|
|
|
|
|
|
|
|
if (!sps->page_shift) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((sps->page_shift > best_page_shift)
|
|
|
|
&& ((1UL << sps->page_shift) <= rampagesize)) {
|
|
|
|
best_page_shift = sps->page_shift;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-28 08:12:06 +03:00
|
|
|
return 1ULL << (best_page_shift + hash_shift - 7);
|
2012-09-12 20:57:12 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-05-27 09:36:30 +04:00
|
|
|
bool kvmppc_spapr_use_multitce(void)
|
|
|
|
{
|
|
|
|
return cap_spapr_multitce;
|
|
|
|
}
|
|
|
|
|
2017-03-27 08:22:19 +03:00
|
|
|
int kvmppc_spapr_enable_inkernel_multitce(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_ENABLE_HCALL, 0,
|
|
|
|
H_PUT_TCE_INDIRECT, 1);
|
|
|
|
if (!ret) {
|
|
|
|
ret = kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_ENABLE_HCALL, 0,
|
|
|
|
H_STUFF_TCE, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-10 04:41:13 +03:00
|
|
|
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t page_shift,
|
|
|
|
uint64_t bus_offset, uint32_t nb_table,
|
|
|
|
int *pfd, bool need_vfio)
|
2011-09-30 01:39:12 +04:00
|
|
|
{
|
|
|
|
long len;
|
|
|
|
int fd;
|
|
|
|
void *table;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* Must set fd to -1 so we don't try to munmap when called for
|
pseries: Don't try to munmap() a malloc()ed TCE table
For the pseries machine, TCE (IOMMU) tables can either be directly
malloc()ed in qemu or, when running on a KVM which supports it, mmap()ed
from a KVM ioctl. The latter option is used when available, because it
allows the (frequent bottlenext) H_PUT_TCE hypercall to be KVM accelerated.
However, even when KVM is persent, TCE acceleration is not always possible.
Only KVM HV supports this ioctl(), not KVM PR, or the kernel could run out
of contiguous memory to allocate the new table. In this case we need to
fall back on the malloc()ed table.
When a device is removed, and we need to remove the TCE table, we need to
either munmap() or free() the table as appropriate for how it was
allocated. The code is supposed to do that, but we buggily fail to
initialize the tcet->fd variable in the malloc() case, which is used as a
flag to determine which is the right choice.
This patch fixes the bug, and cleans up error messages relating to this
path while we're at it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-02-27 21:18:07 +04:00
|
|
|
* destroying the table, which the upper layers -will- do
|
|
|
|
*/
|
|
|
|
*pfd = -1;
|
2015-09-30 06:42:55 +03:00
|
|
|
if (!cap_spapr_tce || (need_vfio && !cap_spapr_vfio)) {
|
2011-09-30 01:39:12 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-10 04:41:13 +03:00
|
|
|
if (cap_spapr_tce_64) {
|
|
|
|
struct kvm_create_spapr_tce_64 args = {
|
|
|
|
.liobn = liobn,
|
|
|
|
.page_shift = page_shift,
|
|
|
|
.offset = bus_offset >> page_shift,
|
|
|
|
.size = nb_table,
|
|
|
|
.flags = 0
|
|
|
|
};
|
|
|
|
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE_64, &args);
|
|
|
|
if (fd < 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"KVM: Failed to create TCE64 table for liobn 0x%x\n",
|
|
|
|
liobn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else if (cap_spapr_tce) {
|
|
|
|
uint64_t window_size = (uint64_t) nb_table << page_shift;
|
|
|
|
struct kvm_create_spapr_tce args = {
|
|
|
|
.liobn = liobn,
|
|
|
|
.window_size = window_size,
|
|
|
|
};
|
|
|
|
if ((window_size != args.window_size) || bus_offset) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
fd = kvm_vm_ioctl(kvm_state, KVM_CREATE_SPAPR_TCE, &args);
|
|
|
|
if (fd < 0) {
|
|
|
|
fprintf(stderr, "KVM: Failed to create TCE table for liobn 0x%x\n",
|
|
|
|
liobn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
2011-09-30 01:39:12 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-03-10 04:41:13 +03:00
|
|
|
len = nb_table * sizeof(uint64_t);
|
2011-09-30 01:39:12 +04:00
|
|
|
/* FIXME: round this up to page size */
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
table = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
2011-09-30 01:39:12 +04:00
|
|
|
if (table == MAP_FAILED) {
|
pseries: Don't try to munmap() a malloc()ed TCE table
For the pseries machine, TCE (IOMMU) tables can either be directly
malloc()ed in qemu or, when running on a KVM which supports it, mmap()ed
from a KVM ioctl. The latter option is used when available, because it
allows the (frequent bottlenext) H_PUT_TCE hypercall to be KVM accelerated.
However, even when KVM is persent, TCE acceleration is not always possible.
Only KVM HV supports this ioctl(), not KVM PR, or the kernel could run out
of contiguous memory to allocate the new table. In this case we need to
fall back on the malloc()ed table.
When a device is removed, and we need to remove the TCE table, we need to
either munmap() or free() the table as appropriate for how it was
allocated. The code is supposed to do that, but we buggily fail to
initialize the tcet->fd variable in the malloc() case, which is used as a
flag to determine which is the right choice.
This patch fixes the bug, and cleans up error messages relating to this
path while we're at it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-02-27 21:18:07 +04:00
|
|
|
fprintf(stderr, "KVM: Failed to map TCE table for liobn 0x%x\n",
|
|
|
|
liobn);
|
2011-09-30 01:39:12 +04:00
|
|
|
close(fd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pfd = fd;
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
2014-05-27 09:36:35 +04:00
|
|
|
int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t nb_table)
|
2011-09-30 01:39:12 +04:00
|
|
|
{
|
|
|
|
long len;
|
|
|
|
|
|
|
|
if (fd < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-05-27 09:36:35 +04:00
|
|
|
len = nb_table * sizeof(uint64_t);
|
2011-09-30 01:39:12 +04:00
|
|
|
if ((munmap(table, len) < 0) ||
|
|
|
|
(close(fd) < 0)) {
|
pseries: Don't try to munmap() a malloc()ed TCE table
For the pseries machine, TCE (IOMMU) tables can either be directly
malloc()ed in qemu or, when running on a KVM which supports it, mmap()ed
from a KVM ioctl. The latter option is used when available, because it
allows the (frequent bottlenext) H_PUT_TCE hypercall to be KVM accelerated.
However, even when KVM is persent, TCE acceleration is not always possible.
Only KVM HV supports this ioctl(), not KVM PR, or the kernel could run out
of contiguous memory to allocate the new table. In this case we need to
fall back on the malloc()ed table.
When a device is removed, and we need to remove the TCE table, we need to
either munmap() or free() the table as appropriate for how it was
allocated. The code is supposed to do that, but we buggily fail to
initialize the tcet->fd variable in the malloc() case, which is used as a
flag to determine which is the right choice.
This patch fixes the bug, and cleans up error messages relating to this
path while we're at it.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
2012-02-27 21:18:07 +04:00
|
|
|
fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",
|
|
|
|
strerror(errno));
|
2011-09-30 01:39:12 +04:00
|
|
|
/* Leak the table */
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-12 20:57:12 +04:00
|
|
|
int kvmppc_reset_htab(int shift_hint)
|
|
|
|
{
|
|
|
|
uint32_t shift = shift_hint;
|
|
|
|
|
2012-09-20 01:08:42 +04:00
|
|
|
if (!kvm_enabled()) {
|
|
|
|
/* Full emulation, tell caller to allocate htab itself */
|
|
|
|
return 0;
|
|
|
|
}
|
2017-09-14 22:25:43 +03:00
|
|
|
if (kvm_vm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) {
|
2012-09-12 20:57:12 +04:00
|
|
|
int ret;
|
|
|
|
ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift);
|
2012-09-20 01:08:42 +04:00
|
|
|
if (ret == -ENOTTY) {
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* At least some versions of PR KVM advertise the
|
2012-09-20 01:08:42 +04:00
|
|
|
* capability, but don't implement the ioctl(). Oops.
|
|
|
|
* Return 0 so that we allocate the htab in qemu, as is
|
2019-03-21 13:47:25 +03:00
|
|
|
* correct for PR.
|
|
|
|
*/
|
2012-09-20 01:08:42 +04:00
|
|
|
return 0;
|
|
|
|
} else if (ret < 0) {
|
2012-09-12 20:57:12 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return shift;
|
|
|
|
}
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
/*
|
|
|
|
* We have a kernel that predates the htab reset calls. For PR
|
2012-09-20 01:08:42 +04:00
|
|
|
* KVM, we need to allocate the htab ourselves, for an HV KVM of
|
2019-03-21 13:47:25 +03:00
|
|
|
* this era, it has allocated a 16MB fixed size hash table
|
|
|
|
* already.
|
|
|
|
*/
|
2016-09-29 13:48:06 +03:00
|
|
|
if (kvmppc_is_pr(kvm_state)) {
|
2012-09-20 01:08:42 +04:00
|
|
|
/* PR - tell caller to allocate htab */
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* HV - assume 16MB kernel allocated htab */
|
|
|
|
return 24;
|
|
|
|
}
|
2012-09-12 20:57:12 +04:00
|
|
|
}
|
|
|
|
|
2011-10-13 02:40:32 +04:00
|
|
|
static inline uint32_t mfpvr(void)
|
|
|
|
{
|
|
|
|
uint32_t pvr;
|
|
|
|
|
|
|
|
asm ("mfpvr %0"
|
|
|
|
: "=r"(pvr));
|
|
|
|
return pvr;
|
|
|
|
}
|
|
|
|
|
2011-10-17 22:15:41 +04:00
|
|
|
static void alter_insns(uint64_t *word, uint64_t flags, bool on)
|
|
|
|
{
|
|
|
|
if (on) {
|
|
|
|
*word |= flags;
|
|
|
|
} else {
|
|
|
|
*word &= ~flags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-06 12:31:30 +04:00
|
|
|
static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
2013-04-07 23:08:19 +04:00
|
|
|
uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size");
|
|
|
|
uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size");
|
2011-10-13 02:40:32 +04:00
|
|
|
|
2013-02-18 03:16:41 +04:00
|
|
|
/* Now fix up the class with information we can query from the host */
|
2013-09-27 12:05:03 +04:00
|
|
|
pcc->pvr = mfpvr();
|
2011-10-17 22:15:41 +04:00
|
|
|
|
2017-12-11 09:41:34 +03:00
|
|
|
alter_insns(&pcc->insns_flags, PPC_ALTIVEC,
|
|
|
|
qemu_getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC);
|
|
|
|
alter_insns(&pcc->insns_flags2, PPC2_VSX,
|
|
|
|
qemu_getauxval(AT_HWCAP) & PPC_FEATURE_HAS_VSX);
|
|
|
|
alter_insns(&pcc->insns_flags2, PPC2_DFP,
|
|
|
|
qemu_getauxval(AT_HWCAP) & PPC_FEATURE_HAS_DFP);
|
2013-04-07 23:08:19 +04:00
|
|
|
|
|
|
|
if (dcache_size != -1) {
|
|
|
|
pcc->l1_dcache_size = dcache_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (icache_size != -1) {
|
|
|
|
pcc->l1_icache_size = icache_size;
|
|
|
|
}
|
2017-03-20 02:46:43 +03:00
|
|
|
|
|
|
|
#if defined(TARGET_PPC64)
|
2023-09-08 19:42:04 +03:00
|
|
|
pcc->radix_page_info = kvmppc_get_radix_page_info();
|
2017-03-20 02:46:43 +03:00
|
|
|
#endif /* defined(TARGET_PPC64) */
|
2011-10-13 02:40:32 +04:00
|
|
|
}
|
|
|
|
|
2013-03-30 10:40:49 +04:00
|
|
|
bool kvmppc_has_cap_epr(void)
|
|
|
|
{
|
|
|
|
return cap_epr;
|
|
|
|
}
|
|
|
|
|
2014-06-04 14:14:08 +04:00
|
|
|
bool kvmppc_has_cap_fixup_hcalls(void)
|
|
|
|
{
|
|
|
|
return cap_fixup_hcalls;
|
|
|
|
}
|
|
|
|
|
2016-09-28 14:16:30 +03:00
|
|
|
bool kvmppc_has_cap_htm(void)
|
|
|
|
{
|
|
|
|
return cap_htm;
|
|
|
|
}
|
|
|
|
|
2017-03-20 02:46:44 +03:00
|
|
|
bool kvmppc_has_cap_mmu_radix(void)
|
|
|
|
{
|
|
|
|
return cap_mmu_radix;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool kvmppc_has_cap_mmu_hash_v3(void)
|
|
|
|
{
|
|
|
|
return cap_mmu_hash_v3;
|
|
|
|
}
|
|
|
|
|
2018-06-12 08:16:29 +03:00
|
|
|
static bool kvmppc_power8_host(void)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
#ifdef TARGET_PPC64
|
|
|
|
{
|
|
|
|
uint32_t base_pvr = CPU_POWERPC_POWER_SERVER_MASK & mfpvr();
|
|
|
|
ret = (base_pvr == CPU_POWERPC_POWER8E_BASE) ||
|
|
|
|
(base_pvr == CPU_POWERPC_POWER8NVL_BASE) ||
|
|
|
|
(base_pvr == CPU_POWERPC_POWER8_BASE);
|
|
|
|
}
|
|
|
|
#endif /* TARGET_PPC64 */
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-05-11 09:25:07 +03:00
|
|
|
static int parse_cap_ppc_safe_cache(struct kvm_ppc_cpu_char c)
|
|
|
|
{
|
2018-06-12 08:16:29 +03:00
|
|
|
bool l1d_thread_priv_req = !kvmppc_power8_host();
|
|
|
|
|
2018-05-11 09:25:07 +03:00
|
|
|
if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_L1D_FLUSH_PR) {
|
|
|
|
return 2;
|
2018-06-12 08:16:29 +03:00
|
|
|
} else if ((!l1d_thread_priv_req ||
|
|
|
|
c.character & c.character_mask & H_CPU_CHAR_L1D_THREAD_PRIV) &&
|
2018-05-11 09:25:07 +03:00
|
|
|
(c.character & c.character_mask
|
|
|
|
& (H_CPU_CHAR_L1D_FLUSH_ORI30 | H_CPU_CHAR_L1D_FLUSH_TRIG2))) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_cap_ppc_safe_bounds_check(struct kvm_ppc_cpu_char c)
|
|
|
|
{
|
|
|
|
if (~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR) {
|
|
|
|
return 2;
|
|
|
|
} else if (c.character & c.character_mask & H_CPU_CHAR_SPEC_BAR_ORI31) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_cap_ppc_safe_indirect_branch(struct kvm_ppc_cpu_char c)
|
|
|
|
{
|
2019-03-01 06:19:11 +03:00
|
|
|
if ((~c.behaviour & c.behaviour_mask & H_CPU_BEHAV_FLUSH_COUNT_CACHE) &&
|
|
|
|
(~c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) &&
|
|
|
|
(~c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED)) {
|
|
|
|
return SPAPR_CAP_FIXED_NA;
|
|
|
|
} else if (c.behaviour & c.behaviour_mask & H_CPU_BEHAV_FLUSH_COUNT_CACHE) {
|
|
|
|
return SPAPR_CAP_WORKAROUND;
|
|
|
|
} else if (c.character & c.character_mask & H_CPU_CHAR_CACHE_COUNT_DIS) {
|
2018-05-11 09:25:07 +03:00
|
|
|
return SPAPR_CAP_FIXED_CCD;
|
|
|
|
} else if (c.character & c.character_mask & H_CPU_CHAR_BCCTRL_SERIALISED) {
|
|
|
|
return SPAPR_CAP_FIXED_IBS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-01 06:19:12 +03:00
|
|
|
static int parse_cap_ppc_count_cache_flush_assist(struct kvm_ppc_cpu_char c)
|
|
|
|
{
|
|
|
|
if (c.character & c.character_mask & H_CPU_CHAR_BCCTR_FLUSH_ASSIST) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-13 11:42:33 +03:00
|
|
|
bool kvmppc_has_cap_xive(void)
|
|
|
|
{
|
|
|
|
return cap_xive;
|
|
|
|
}
|
|
|
|
|
2018-01-19 07:59:59 +03:00
|
|
|
static void kvmppc_get_cpu_characteristics(KVMState *s)
|
|
|
|
{
|
|
|
|
struct kvm_ppc_cpu_char c;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Assume broken */
|
|
|
|
cap_ppc_safe_cache = 0;
|
|
|
|
cap_ppc_safe_bounds_check = 0;
|
|
|
|
cap_ppc_safe_indirect_branch = 0;
|
|
|
|
|
|
|
|
ret = kvm_vm_check_extension(s, KVM_CAP_PPC_GET_CPU_CHAR);
|
|
|
|
if (!ret) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ret = kvm_vm_ioctl(s, KVM_PPC_GET_CPU_CHAR, &c);
|
|
|
|
if (ret < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2018-05-11 09:25:07 +03:00
|
|
|
|
|
|
|
cap_ppc_safe_cache = parse_cap_ppc_safe_cache(c);
|
|
|
|
cap_ppc_safe_bounds_check = parse_cap_ppc_safe_bounds_check(c);
|
|
|
|
cap_ppc_safe_indirect_branch = parse_cap_ppc_safe_indirect_branch(c);
|
2019-03-01 06:19:12 +03:00
|
|
|
cap_ppc_count_cache_flush_assist =
|
|
|
|
parse_cap_ppc_count_cache_flush_assist(c);
|
2018-01-19 07:59:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_get_cap_safe_cache(void)
|
|
|
|
{
|
|
|
|
return cap_ppc_safe_cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_get_cap_safe_bounds_check(void)
|
|
|
|
{
|
|
|
|
return cap_ppc_safe_bounds_check;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_get_cap_safe_indirect_branch(void)
|
|
|
|
{
|
|
|
|
return cap_ppc_safe_indirect_branch;
|
|
|
|
}
|
|
|
|
|
2019-03-01 06:19:12 +03:00
|
|
|
int kvmppc_get_cap_count_cache_flush_assist(void)
|
|
|
|
{
|
|
|
|
return cap_ppc_count_cache_flush_assist;
|
|
|
|
}
|
|
|
|
|
2018-10-08 06:25:39 +03:00
|
|
|
bool kvmppc_has_cap_nested_kvm_hv(void)
|
|
|
|
{
|
|
|
|
return !!cap_ppc_nested_kvm_hv;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_set_cap_nested_kvm_hv(int enable)
|
|
|
|
{
|
|
|
|
return kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_NESTED_HV, 0, enable);
|
|
|
|
}
|
|
|
|
|
2018-02-06 21:08:24 +03:00
|
|
|
bool kvmppc_has_cap_spapr_vfio(void)
|
|
|
|
{
|
|
|
|
return cap_spapr_vfio;
|
|
|
|
}
|
|
|
|
|
2019-03-01 05:43:16 +03:00
|
|
|
int kvmppc_get_cap_large_decr(void)
|
|
|
|
{
|
|
|
|
return cap_large_decr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_enable_cap_large_decr(PowerPCCPU *cpu, int enable)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
2022-03-31 03:17:15 +03:00
|
|
|
uint64_t lpcr = 0;
|
2019-03-01 05:43:16 +03:00
|
|
|
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
|
|
|
|
/* Do we need to modify the LPCR? */
|
|
|
|
if (!!(lpcr & LPCR_LD) != !!enable) {
|
|
|
|
if (enable) {
|
|
|
|
lpcr |= LPCR_LD;
|
|
|
|
} else {
|
|
|
|
lpcr &= ~LPCR_LD;
|
|
|
|
}
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
|
|
|
|
kvm_get_one_reg(cs, KVM_REG_PPC_LPCR_64, &lpcr);
|
|
|
|
|
|
|
|
if (!!(lpcr & LPCR_LD) != !!enable) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-07-06 14:24:40 +03:00
|
|
|
int kvmppc_has_cap_rpt_invalidate(void)
|
|
|
|
{
|
|
|
|
return cap_rpt_invalidate;
|
|
|
|
}
|
|
|
|
|
2023-05-15 19:02:16 +03:00
|
|
|
bool kvmppc_supports_ail_3(void)
|
|
|
|
{
|
|
|
|
return cap_ail_mode_3;
|
|
|
|
}
|
|
|
|
|
2016-06-07 18:39:38 +03:00
|
|
|
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
|
|
|
|
{
|
|
|
|
uint32_t host_pvr = mfpvr();
|
|
|
|
PowerPCCPUClass *pvr_pcc;
|
|
|
|
|
|
|
|
pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
|
|
|
|
if (pvr_pcc == NULL) {
|
|
|
|
pvr_pcc = ppc_cpu_class_by_pvr_mask(host_pvr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pvr_pcc;
|
|
|
|
}
|
|
|
|
|
spapr/kvm: Set default cpu model for all machine classes
We have to set the default model of all machine classes, not just for
the active one. Otherwise, "query-machines" will indicate the wrong
CPU model (e.g. "power9_v2.0-powerpc64-cpu" instead of
"host-powerpc64-cpu") as "default-cpu-type".
s390x already fixed this in de60a92e "s390x/kvm: Set default cpu model for
all machine classes". This patch applies a similar fix for the pseries-*
machine types on ppc64.
Doing a
{"execute":"query-machines"}
under KVM now results in
{
"hotpluggable-cpus": true,
"name": "pseries-4.2",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"is-default": true,
"cpu-max": 1024,
"deprecated": false,
"alias": "pseries"
},
{
"hotpluggable-cpus": true,
"name": "pseries-4.1",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"cpu-max": 1024,
"deprecated": false
},
...
Libvirt probes all machines via "-machine none,accel=kvm:tcg" and will
currently see the wrong CPU model under KVM.
Reported-by: Jiři Denemark <jdenemar@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
2019-10-30 19:20:35 +03:00
|
|
|
static void pseries_machine_class_fixup(ObjectClass *oc, void *opaque)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
|
|
|
|
|
|
|
mc->default_cpu_type = TYPE_HOST_POWERPC_CPU;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvm_ppc_register_host_cpu_type(void)
|
2013-02-23 15:22:12 +04:00
|
|
|
{
|
|
|
|
TypeInfo type_info = {
|
|
|
|
.name = TYPE_HOST_POWERPC_CPU,
|
|
|
|
.class_init = kvmppc_host_cpu_class_init,
|
|
|
|
};
|
|
|
|
PowerPCCPUClass *pvr_pcc;
|
2017-07-05 11:49:52 +03:00
|
|
|
ObjectClass *oc;
|
2014-04-11 21:34:25 +04:00
|
|
|
DeviceClass *dc;
|
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
When running with KVM on POWER, we are registering a "family" CPU
type for the host CPU that we are running on. For example, on all
POWER8-compatible hosts, we register a "POWER8" CPU type, so that
you can always start QEMU with "-cpu POWER8" there, without the
need to know whether you are running on a POWER8, POWER8E or POWER8NVL
host machine.
However, we also have a "POWER8" CPU alias in the ppc_cpu_aliases list
(that is mainly useful for TCG). This leads to two cosmetical drawbacks:
If the user runs QEMU with "-cpu ?", we always claim that POWER8 is an
"alias for POWER8_v2.0" - which is simply not true when running with
KVM on POWER. And when using the 'query-cpu-definitions' QMP call,
there are currently two entries for "POWER8", one for the alias, and
one for the additional registered type.
To solve the two problems, we should rather update the "family" alias
instead of registering a new types. We then only have one "POWER8"
CPU definition around, an alias, which also points to the right
destination.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1396536
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-01-31 16:11:58 +03:00
|
|
|
int i;
|
2013-02-23 15:22:12 +04:00
|
|
|
|
2016-06-07 18:39:38 +03:00
|
|
|
pvr_pcc = kvm_ppc_get_host_cpu_class();
|
2013-02-23 15:22:12 +04:00
|
|
|
if (pvr_pcc == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
|
|
|
|
type_register(&type_info);
|
spapr/kvm: Set default cpu model for all machine classes
We have to set the default model of all machine classes, not just for
the active one. Otherwise, "query-machines" will indicate the wrong
CPU model (e.g. "power9_v2.0-powerpc64-cpu" instead of
"host-powerpc64-cpu") as "default-cpu-type".
s390x already fixed this in de60a92e "s390x/kvm: Set default cpu model for
all machine classes". This patch applies a similar fix for the pseries-*
machine types on ppc64.
Doing a
{"execute":"query-machines"}
under KVM now results in
{
"hotpluggable-cpus": true,
"name": "pseries-4.2",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"is-default": true,
"cpu-max": 1024,
"deprecated": false,
"alias": "pseries"
},
{
"hotpluggable-cpus": true,
"name": "pseries-4.1",
"numa-mem-supported": true,
"default-cpu-type": "host-powerpc64-cpu",
"cpu-max": 1024,
"deprecated": false
},
...
Libvirt probes all machines via "-machine none,accel=kvm:tcg" and will
currently see the wrong CPU model under KVM.
Reported-by: Jiři Denemark <jdenemar@redhat.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
Tested-by: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
2019-10-30 19:20:35 +03:00
|
|
|
/* override TCG default cpu type with 'host' cpu model */
|
|
|
|
object_class_foreach(pseries_machine_class_fixup, TYPE_SPAPR_MACHINE,
|
|
|
|
false, NULL);
|
2014-04-11 21:34:25 +04:00
|
|
|
|
2017-07-05 11:49:52 +03:00
|
|
|
oc = object_class_by_name(type_info.name);
|
|
|
|
g_assert(oc);
|
|
|
|
|
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
When running with KVM on POWER, we are registering a "family" CPU
type for the host CPU that we are running on. For example, on all
POWER8-compatible hosts, we register a "POWER8" CPU type, so that
you can always start QEMU with "-cpu POWER8" there, without the
need to know whether you are running on a POWER8, POWER8E or POWER8NVL
host machine.
However, we also have a "POWER8" CPU alias in the ppc_cpu_aliases list
(that is mainly useful for TCG). This leads to two cosmetical drawbacks:
If the user runs QEMU with "-cpu ?", we always claim that POWER8 is an
"alias for POWER8_v2.0" - which is simply not true when running with
KVM on POWER. And when using the 'query-cpu-definitions' QMP call,
there are currently two entries for "POWER8", one for the alias, and
one for the additional registered type.
To solve the two problems, we should rather update the "family" alias
instead of registering a new types. We then only have one "POWER8"
CPU definition around, an alias, which also points to the right
destination.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1396536
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-01-31 16:11:58 +03:00
|
|
|
/*
|
|
|
|
* Update generic CPU family class alias (e.g. on a POWER8NVL host,
|
|
|
|
* we want "POWER8" to be a "family" alias that points to the current
|
|
|
|
* host CPU type, too)
|
|
|
|
*/
|
|
|
|
dc = DEVICE_CLASS(ppc_cpu_get_family_class(pvr_pcc));
|
|
|
|
for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
|
2017-08-30 16:24:30 +03:00
|
|
|
if (strcasecmp(ppc_cpu_aliases[i].alias, dc->desc) == 0) {
|
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
When running with KVM on POWER, we are registering a "family" CPU
type for the host CPU that we are running on. For example, on all
POWER8-compatible hosts, we register a "POWER8" CPU type, so that
you can always start QEMU with "-cpu POWER8" there, without the
need to know whether you are running on a POWER8, POWER8E or POWER8NVL
host machine.
However, we also have a "POWER8" CPU alias in the ppc_cpu_aliases list
(that is mainly useful for TCG). This leads to two cosmetical drawbacks:
If the user runs QEMU with "-cpu ?", we always claim that POWER8 is an
"alias for POWER8_v2.0" - which is simply not true when running with
KVM on POWER. And when using the 'query-cpu-definitions' QMP call,
there are currently two entries for "POWER8", one for the alias, and
one for the additional registered type.
To solve the two problems, we should rather update the "family" alias
instead of registering a new types. We then only have one "POWER8"
CPU definition around, an alias, which also points to the right
destination.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1396536
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-01-31 16:11:58 +03:00
|
|
|
char *suffix;
|
|
|
|
|
|
|
|
ppc_cpu_aliases[i].model = g_strdup(object_class_get_name(oc));
|
2017-08-30 16:24:29 +03:00
|
|
|
suffix = strstr(ppc_cpu_aliases[i].model, POWERPC_CPU_TYPE_SUFFIX);
|
ppc/kvm: Handle the "family" CPU via alias instead of registering new types
When running with KVM on POWER, we are registering a "family" CPU
type for the host CPU that we are running on. For example, on all
POWER8-compatible hosts, we register a "POWER8" CPU type, so that
you can always start QEMU with "-cpu POWER8" there, without the
need to know whether you are running on a POWER8, POWER8E or POWER8NVL
host machine.
However, we also have a "POWER8" CPU alias in the ppc_cpu_aliases list
(that is mainly useful for TCG). This leads to two cosmetical drawbacks:
If the user runs QEMU with "-cpu ?", we always claim that POWER8 is an
"alias for POWER8_v2.0" - which is simply not true when running with
KVM on POWER. And when using the 'query-cpu-definitions' QMP call,
there are currently two entries for "POWER8", one for the alias, and
one for the additional registered type.
To solve the two problems, we should rather update the "family" alias
instead of registering a new types. We then only have one "POWER8"
CPU definition around, an alias, which also points to the right
destination.
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1396536
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-01-31 16:11:58 +03:00
|
|
|
if (suffix) {
|
|
|
|
*suffix = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-23 15:22:12 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-26 10:18:35 +04:00
|
|
|
int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function)
|
|
|
|
{
|
|
|
|
struct kvm_rtas_token_args args = {
|
|
|
|
.token = token,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!kvm_check_extension(kvm_state, KVM_CAP_PPC_RTAS)) {
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2019-06-15 11:12:52 +03:00
|
|
|
strncpy(args.name, function, sizeof(args.name) - 1);
|
2013-09-26 10:18:35 +04:00
|
|
|
|
|
|
|
return kvm_vm_ioctl(kvm_state, KVM_PPC_RTAS_DEFINE_TOKEN, &args);
|
|
|
|
}
|
2012-04-04 09:02:05 +04:00
|
|
|
|
2017-09-15 16:16:20 +03:00
|
|
|
int kvmppc_get_htab_fd(bool write, uint64_t index, Error **errp)
|
2013-07-18 23:33:03 +04:00
|
|
|
{
|
|
|
|
struct kvm_get_htab_fd s = {
|
|
|
|
.flags = write ? KVM_GET_HTAB_WRITE : 0,
|
2017-09-15 16:16:20 +03:00
|
|
|
.start_index = index,
|
2013-07-18 23:33:03 +04:00
|
|
|
};
|
2017-09-15 16:16:10 +03:00
|
|
|
int ret;
|
2013-07-18 23:33:03 +04:00
|
|
|
|
|
|
|
if (!cap_htab_fd) {
|
2017-09-15 16:16:20 +03:00
|
|
|
error_setg(errp, "KVM version doesn't support %s the HPT",
|
|
|
|
write ? "writing" : "reading");
|
2017-09-15 16:16:10 +03:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &s);
|
|
|
|
if (ret < 0) {
|
2017-09-15 16:16:20 +03:00
|
|
|
error_setg(errp, "Unable to open fd for %s HPT %s KVM: %s",
|
|
|
|
write ? "writing" : "reading", write ? "to" : "from",
|
|
|
|
strerror(errno));
|
2017-09-15 16:16:10 +03:00
|
|
|
return -errno;
|
2013-07-18 23:33:03 +04:00
|
|
|
}
|
|
|
|
|
2017-09-15 16:16:10 +03:00
|
|
|
return ret;
|
2013-07-18 23:33:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns)
|
|
|
|
{
|
2013-08-21 19:03:08 +04:00
|
|
|
int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
|
2024-02-21 19:26:34 +03:00
|
|
|
g_autofree uint8_t *buf = g_malloc(bufsize);
|
2013-07-18 23:33:03 +04:00
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
do {
|
|
|
|
rc = read(fd, buf, bufsize);
|
|
|
|
if (rc < 0) {
|
|
|
|
fprintf(stderr, "Error reading data from KVM HTAB fd: %s\n",
|
|
|
|
strerror(errno));
|
|
|
|
return rc;
|
|
|
|
} else if (rc) {
|
2014-11-03 18:14:50 +03:00
|
|
|
uint8_t *buffer = buf;
|
|
|
|
ssize_t n = rc;
|
|
|
|
while (n) {
|
|
|
|
struct kvm_get_htab_header *head =
|
|
|
|
(struct kvm_get_htab_header *) buffer;
|
|
|
|
size_t chunksize = sizeof(*head) +
|
|
|
|
HASH_PTE_SIZE_64 * head->n_valid;
|
|
|
|
|
|
|
|
qemu_put_be32(f, head->index);
|
|
|
|
qemu_put_be16(f, head->n_valid);
|
|
|
|
qemu_put_be16(f, head->n_invalid);
|
|
|
|
qemu_put_buffer(f, (void *)(head + 1),
|
|
|
|
HASH_PTE_SIZE_64 * head->n_valid);
|
|
|
|
|
|
|
|
buffer += chunksize;
|
|
|
|
n -= chunksize;
|
|
|
|
}
|
2013-07-18 23:33:03 +04:00
|
|
|
}
|
|
|
|
} while ((rc != 0)
|
2019-03-21 13:47:25 +03:00
|
|
|
&& ((max_ns < 0) ||
|
|
|
|
((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) < max_ns)));
|
2013-07-18 23:33:03 +04:00
|
|
|
|
|
|
|
return (rc == 0) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
|
2020-10-26 15:40:47 +03:00
|
|
|
uint16_t n_valid, uint16_t n_invalid, Error **errp)
|
2013-07-18 23:33:03 +04:00
|
|
|
{
|
|
|
|
struct kvm_get_htab_header *buf;
|
2019-03-21 13:47:25 +03:00
|
|
|
size_t chunksize = sizeof(*buf) + n_valid * HASH_PTE_SIZE_64;
|
2013-07-18 23:33:03 +04:00
|
|
|
ssize_t rc;
|
|
|
|
|
|
|
|
buf = alloca(chunksize);
|
|
|
|
buf->index = index;
|
|
|
|
buf->n_valid = n_valid;
|
|
|
|
buf->n_invalid = n_invalid;
|
|
|
|
|
2019-03-21 13:47:25 +03:00
|
|
|
qemu_get_buffer(f, (void *)(buf + 1), HASH_PTE_SIZE_64 * n_valid);
|
2013-07-18 23:33:03 +04:00
|
|
|
|
|
|
|
rc = write(fd, buf, chunksize);
|
|
|
|
if (rc < 0) {
|
2020-10-26 15:40:47 +03:00
|
|
|
error_setg_errno(errp, errno, "Error writing the KVM hash table");
|
|
|
|
return -errno;
|
2013-07-18 23:33:03 +04:00
|
|
|
}
|
|
|
|
if (rc != chunksize) {
|
|
|
|
/* We should never get a short write on a single chunk */
|
2020-10-26 15:40:47 +03:00
|
|
|
error_setg(errp, "Short write while restoring the KVM hash table");
|
|
|
|
return -ENOSPC;
|
2013-07-18 23:33:03 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:57:49 +04:00
|
|
|
bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
|
2010-05-10 12:21:34 +04:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2011-02-02 00:15:51 +03:00
|
|
|
|
2013-06-12 11:26:54 +04:00
|
|
|
void kvm_arch_init_irq_routing(KVMState *s)
|
|
|
|
{
|
|
|
|
}
|
2013-12-11 17:15:34 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n)
|
2014-02-20 21:52:24 +04:00
|
|
|
{
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
int fd, rc;
|
|
|
|
int i;
|
2014-02-20 21:52:24 +04:00
|
|
|
|
2017-09-15 16:16:20 +03:00
|
|
|
fd = kvmppc_get_htab_fd(false, ptex, &error_abort);
|
2014-02-20 21:52:24 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
i = 0;
|
|
|
|
while (i < n) {
|
|
|
|
struct kvm_get_htab_header *hdr;
|
|
|
|
int m = n < HPTES_PER_GROUP ? n : HPTES_PER_GROUP;
|
2024-02-21 19:26:35 +03:00
|
|
|
char buf[sizeof(*hdr) + HPTES_PER_GROUP * HASH_PTE_SIZE_64];
|
2014-02-20 21:52:24 +04:00
|
|
|
|
2024-02-21 19:26:35 +03:00
|
|
|
rc = read(fd, buf, sizeof(*hdr) + m * HASH_PTE_SIZE_64);
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
if (rc < 0) {
|
|
|
|
hw_error("kvmppc_read_hptes: Unable to read HPTEs");
|
|
|
|
}
|
2014-02-20 21:52:24 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
hdr = (struct kvm_get_htab_header *)buf;
|
|
|
|
while ((i < n) && ((char *)hdr < (buf + rc))) {
|
2018-01-11 07:08:32 +03:00
|
|
|
int invalid = hdr->n_invalid, valid = hdr->n_valid;
|
2014-02-20 21:52:24 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
if (hdr->index != (ptex + i)) {
|
|
|
|
hw_error("kvmppc_read_hptes: Unexpected HPTE index %"PRIu32
|
|
|
|
" != (%"HWADDR_PRIu" + %d", hdr->index, ptex, i);
|
|
|
|
}
|
|
|
|
|
2018-01-11 07:08:32 +03:00
|
|
|
if (n - i < valid) {
|
|
|
|
valid = n - i;
|
|
|
|
}
|
|
|
|
memcpy(hptes + i, hdr + 1, HASH_PTE_SIZE_64 * valid);
|
|
|
|
i += valid;
|
2014-02-20 21:52:24 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
if ((n - i) < invalid) {
|
|
|
|
invalid = n - i;
|
|
|
|
}
|
|
|
|
memset(hptes + i, 0, invalid * HASH_PTE_SIZE_64);
|
2018-01-11 07:08:32 +03:00
|
|
|
i += invalid;
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
|
|
|
|
hdr = (struct kvm_get_htab_header *)
|
|
|
|
((char *)(hdr + 1) + HASH_PTE_SIZE_64 * hdr->n_valid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
2014-02-20 21:52:24 +04:00
|
|
|
}
|
2014-02-20 21:52:38 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1)
|
2014-02-20 21:52:38 +04:00
|
|
|
{
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
int fd, rc;
|
|
|
|
struct {
|
|
|
|
struct kvm_get_htab_header hdr;
|
|
|
|
uint64_t pte0;
|
|
|
|
uint64_t pte1;
|
|
|
|
} buf;
|
2014-02-20 21:52:38 +04:00
|
|
|
|
2017-09-15 16:16:20 +03:00
|
|
|
fd = kvmppc_get_htab_fd(true, 0 /* Ignored */, &error_abort);
|
2014-02-20 21:52:38 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
buf.hdr.n_valid = 1;
|
|
|
|
buf.hdr.n_invalid = 0;
|
|
|
|
buf.hdr.index = ptex;
|
|
|
|
buf.pte0 = cpu_to_be64(pte0);
|
|
|
|
buf.pte1 = cpu_to_be64(pte1);
|
2014-02-20 21:52:38 +04:00
|
|
|
|
target/ppc: Fix KVM-HV HPTE accessors
When a 'pseries' guest is running with KVM-HV, the guest's hashed page
table (HPT) is stored within the host kernel, so it is not directly
accessible to qemu. Most of the time, qemu doesn't need to access it:
we're using the hardware MMU, and KVM itself implements the guest
hypercalls for manipulating the HPT.
However, qemu does need access to the in-KVM HPT to implement
get_phys_page_debug() for the benefit of the gdbstub, and maybe for
other debug operations.
To allow this, 7c43bca "target-ppc: Fix page table lookup with kvm
enabled" added kvmppc_hash64_read_pteg() to target/ppc/kvm.c to read
in a batch of HPTEs from the KVM table. Unfortunately, there are a
couple of problems with this:
First, the name of the function implies it always reads a whole PTEG
from the HPT, but in fact in some cases it's used to grab individual
HPTEs (which ends up pulling 8 HPTEs, not aligned to a PTEG from the
kernel).
Second, and more importantly, the code to read the HPTEs from KVM is
simply wrong, in general. The data from the fd that KVM provides is
designed mostly for compact migration rather than this sort of one-off
access, and so needs some decoding for this purpose. The current code
will work in some cases, but if there are invalid HPTEs then it will
not get sane results.
This patch rewrite the HPTE reading function to have a simpler
interface (just read n HPTEs into a caller provided buffer), and to
correctly decode the stream from the kernel.
For consistency we also clean up the similar function for altering
HPTEs within KVM (introduced in c138593 "target-ppc: Update
ppc_hash64_store_hpte to support updating in-kernel htab").
Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2017-02-27 07:34:19 +03:00
|
|
|
rc = write(fd, &buf, sizeof(buf));
|
|
|
|
if (rc != sizeof(buf)) {
|
|
|
|
hw_error("kvmppc_write_hpte: Unable to update KVM HPT");
|
|
|
|
}
|
|
|
|
close(fd);
|
2014-02-20 21:52:38 +04:00
|
|
|
}
|
2015-01-09 11:04:40 +03:00
|
|
|
|
|
|
|
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
|
2015-10-15 16:44:52 +03:00
|
|
|
uint64_t address, uint32_t data, PCIDevice *dev)
|
2015-01-09 11:04:40 +03:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-02 16:56:23 +03:00
|
|
|
|
2016-07-14 08:56:31 +03:00
|
|
|
int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
|
|
|
|
int vector, PCIDevice *dev)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_arch_release_virq_post(int virq)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-06-02 16:56:23 +03:00
|
|
|
int kvm_arch_msi_data_to_gsi(uint32_t data)
|
|
|
|
{
|
|
|
|
return data & 0xffff;
|
|
|
|
}
|
ppc/spapr: Implement H_RANDOM hypercall in QEMU
The PAPR interface defines a hypercall to pass high-quality
hardware generated random numbers to guests. Recent kernels can
already provide this hypercall to the guest if the right hardware
random number generator is available. But in case the user wants
to use another source like EGD, or QEMU is running with an older
kernel, we should also have this call in QEMU, so that guests that
do not support virtio-rng yet can get good random numbers, too.
This patch now adds a new pseudo-device to QEMU that either
directly provides this hypercall to the guest or is able to
enable the in-kernel hypercall if available. The in-kernel
hypercall can be enabled with the use-kvm property, e.g.:
qemu-system-ppc64 -device spapr-rng,use-kvm=true
For handling the hypercall in QEMU instead, a "RngBackend" is
required since the hypercall should provide "good" random data
instead of pseudo-random (like from a "simple" library function
like rand() or g_random_int()). Since there are multiple RngBackends
available, the user must select an appropriate back-end via the
"rng" property of the device, e.g.:
qemu-system-ppc64 -object rng-random,filename=/dev/hwrng,id=gid0 \
-device spapr-rng,rng=gid0 ...
See http://wiki.qemu-project.org/Features-Done/VirtIORNG for
other example of specifying RngBackends.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2015-09-17 11:49:41 +03:00
|
|
|
|
2020-01-30 21:44:19 +03:00
|
|
|
#if defined(TARGET_PPC64)
|
|
|
|
int kvm_handle_nmi(PowerPCCPU *cpu, struct kvm_run *run)
|
|
|
|
{
|
target/ppc: Fix wrong interpretation of the disposition flag.
Bitwise AND with kvm_run->flags to evaluate if we recovered from
MCE or not is not correct, As disposition in kvm_run->flags is a
two-bit integer value and not a bit map, So check for equality
instead of bitwise AND.
Without the fix qemu treats any unrecoverable mce error as recoverable
and ends up in a mce loop inside the guest, Below are the MCE logs before
and after the fix.
Before fix:
[ 66.775757] MCE: CPU0: Initiator CPU
[ 66.775891] MCE: CPU0: Unknown
[ 66.776587] MCE: CPU0: machine check (Harmless) Host UE Indeterminate [Recovered]
[ 66.776857] MCE: CPU0: NIP: [c0080000000e00b8] mcetest_tlbie+0xb0/0x128 [mcetest_tlbie]
After fix:
[ 20.650577] CPU: 0 PID: 1415 Comm: insmod Tainted: G M O 5.6.0-fwnmi-arv+ #11
[ 20.650618] NIP: c0080000023a00e8 LR: c0080000023a00d8 CTR: c000000000021fe0
[ 20.650660] REGS: c0000001fffd3d70 TRAP: 0200 Tainted: G M O (5.6.0-fwnmi-arv+)
[ 20.650708] MSR: 8000000002a0b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 42000222 XER: 20040000
[ 20.650758] CFAR: c00000000000b940 DAR: c0080000025e00e0 DSISR: 00000200 IRQMASK: 0
[ 20.650758] GPR00: c0080000023a00d8 c0000001fddd79a0 c0080000023a8500 0000000000000039
[ 20.650758] GPR04: 0000000000000001 0000000000000000 0000000000000000 0000000000000007
[ 20.650758] GPR08: 0000000000000007 c0080000025e00e0 0000000000000000 00000000000000f7
[ 20.650758] GPR12: 0000000000000000 c000000001900000 c00000000101f398 c0080000025c052f
[ 20.650758] GPR16: 00000000000003a8 c0080000025c0000 c0000001fddd7d70 c0000000015b7940
[ 20.650758] GPR20: 000000000000fff1 c000000000f72c28 c0080000025a0988 0000000000000000
[ 20.650758] GPR24: 0000000000000100 c0080000023a05d0 c0000000001f1d70 0000000000000000
[ 20.650758] GPR28: c0000001fde20000 c0000001fd02b2e0 c0080000023a0000 c0080000025e0000
[ 20.651178] NIP [c0080000023a00e8] mcetest_tlbie+0xe8/0xf0 [mcetest_tlbie]
[ 20.651220] LR [c0080000023a00d8] mcetest_tlbie+0xd8/0xf0 [mcetest_tlbie]
[ 20.651262] Call Trace:
[ 20.651280] [c0000001fddd79a0] [c0080000023a00d8] mcetest_tlbie+0xd8/0xf0 [mcetest_tlbie] (unreliable)
[ 20.651340] [c0000001fddd7a10] [c00000000001091c] do_one_initcall+0x6c/0x2c0
[ 20.651390] [c0000001fddd7af0] [c0000000001f7998] do_init_module+0x90/0x298
[ 20.651433] [c0000001fddd7b80] [c0000000001f61a8] load_module+0x1f58/0x27a0
[ 20.651476] [c0000001fddd7d40] [c0000000001f6c70] __do_sys_finit_module+0xe0/0x100
[ 20.651526] [c0000001fddd7e20] [c00000000000b9d0] system_call+0x5c/0x68
[ 20.651567] Instruction dump:
[ 20.651594] e8410018 3c620000 e8638020 480000cd e8410018 3c620000 e8638028 480000bd
[ 20.651646] e8410018 7be904e4 39400000 612900e0 <7d434a64> 4bffff74 3c4c0001 38428410
[ 20.651699] ---[ end trace 4c40897f016b4340 ]---
[ 20.653310]
Bus error
[ 20.655575] MCE: CPU0: machine check (Harmless) Host UE Indeterminate [Not recovered]
[ 20.655575] MCE: CPU0: NIP: [c0080000023a00e8] mcetest_tlbie+0xe8/0xf0 [mcetest_tlbie]
[ 20.655576] MCE: CPU0: Initiator CPU
[ 20.655576] MCE: CPU0: Unknown
Signed-off-by: Ganesh Goudar <ganeshgr@linux.ibm.com>
Message-Id: <20200408170944.16003-1-ganeshgr@linux.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-04-08 20:09:44 +03:00
|
|
|
uint16_t flags = run->flags & KVM_RUN_PPC_NMI_DISP_MASK;
|
2020-01-30 21:44:20 +03:00
|
|
|
|
2020-01-30 21:44:19 +03:00
|
|
|
cpu_synchronize_state(CPU(cpu));
|
|
|
|
|
target/ppc: Fix wrong interpretation of the disposition flag.
Bitwise AND with kvm_run->flags to evaluate if we recovered from
MCE or not is not correct, As disposition in kvm_run->flags is a
two-bit integer value and not a bit map, So check for equality
instead of bitwise AND.
Without the fix qemu treats any unrecoverable mce error as recoverable
and ends up in a mce loop inside the guest, Below are the MCE logs before
and after the fix.
Before fix:
[ 66.775757] MCE: CPU0: Initiator CPU
[ 66.775891] MCE: CPU0: Unknown
[ 66.776587] MCE: CPU0: machine check (Harmless) Host UE Indeterminate [Recovered]
[ 66.776857] MCE: CPU0: NIP: [c0080000000e00b8] mcetest_tlbie+0xb0/0x128 [mcetest_tlbie]
After fix:
[ 20.650577] CPU: 0 PID: 1415 Comm: insmod Tainted: G M O 5.6.0-fwnmi-arv+ #11
[ 20.650618] NIP: c0080000023a00e8 LR: c0080000023a00d8 CTR: c000000000021fe0
[ 20.650660] REGS: c0000001fffd3d70 TRAP: 0200 Tainted: G M O (5.6.0-fwnmi-arv+)
[ 20.650708] MSR: 8000000002a0b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE> CR: 42000222 XER: 20040000
[ 20.650758] CFAR: c00000000000b940 DAR: c0080000025e00e0 DSISR: 00000200 IRQMASK: 0
[ 20.650758] GPR00: c0080000023a00d8 c0000001fddd79a0 c0080000023a8500 0000000000000039
[ 20.650758] GPR04: 0000000000000001 0000000000000000 0000000000000000 0000000000000007
[ 20.650758] GPR08: 0000000000000007 c0080000025e00e0 0000000000000000 00000000000000f7
[ 20.650758] GPR12: 0000000000000000 c000000001900000 c00000000101f398 c0080000025c052f
[ 20.650758] GPR16: 00000000000003a8 c0080000025c0000 c0000001fddd7d70 c0000000015b7940
[ 20.650758] GPR20: 000000000000fff1 c000000000f72c28 c0080000025a0988 0000000000000000
[ 20.650758] GPR24: 0000000000000100 c0080000023a05d0 c0000000001f1d70 0000000000000000
[ 20.650758] GPR28: c0000001fde20000 c0000001fd02b2e0 c0080000023a0000 c0080000025e0000
[ 20.651178] NIP [c0080000023a00e8] mcetest_tlbie+0xe8/0xf0 [mcetest_tlbie]
[ 20.651220] LR [c0080000023a00d8] mcetest_tlbie+0xd8/0xf0 [mcetest_tlbie]
[ 20.651262] Call Trace:
[ 20.651280] [c0000001fddd79a0] [c0080000023a00d8] mcetest_tlbie+0xd8/0xf0 [mcetest_tlbie] (unreliable)
[ 20.651340] [c0000001fddd7a10] [c00000000001091c] do_one_initcall+0x6c/0x2c0
[ 20.651390] [c0000001fddd7af0] [c0000000001f7998] do_init_module+0x90/0x298
[ 20.651433] [c0000001fddd7b80] [c0000000001f61a8] load_module+0x1f58/0x27a0
[ 20.651476] [c0000001fddd7d40] [c0000000001f6c70] __do_sys_finit_module+0xe0/0x100
[ 20.651526] [c0000001fddd7e20] [c00000000000b9d0] system_call+0x5c/0x68
[ 20.651567] Instruction dump:
[ 20.651594] e8410018 3c620000 e8638020 480000cd e8410018 3c620000 e8638028 480000bd
[ 20.651646] e8410018 7be904e4 39400000 612900e0 <7d434a64> 4bffff74 3c4c0001 38428410
[ 20.651699] ---[ end trace 4c40897f016b4340 ]---
[ 20.653310]
Bus error
[ 20.655575] MCE: CPU0: machine check (Harmless) Host UE Indeterminate [Not recovered]
[ 20.655575] MCE: CPU0: NIP: [c0080000023a00e8] mcetest_tlbie+0xe8/0xf0 [mcetest_tlbie]
[ 20.655576] MCE: CPU0: Initiator CPU
[ 20.655576] MCE: CPU0: Unknown
Signed-off-by: Ganesh Goudar <ganeshgr@linux.ibm.com>
Message-Id: <20200408170944.16003-1-ganeshgr@linux.ibm.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2020-04-08 20:09:44 +03:00
|
|
|
spapr_mce_req_event(cpu, flags == KVM_RUN_PPC_NMI_DISP_FULLY_RECOV);
|
2020-01-30 21:44:19 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
ppc/spapr: Implement H_RANDOM hypercall in QEMU
The PAPR interface defines a hypercall to pass high-quality
hardware generated random numbers to guests. Recent kernels can
already provide this hypercall to the guest if the right hardware
random number generator is available. But in case the user wants
to use another source like EGD, or QEMU is running with an older
kernel, we should also have this call in QEMU, so that guests that
do not support virtio-rng yet can get good random numbers, too.
This patch now adds a new pseudo-device to QEMU that either
directly provides this hypercall to the guest or is able to
enable the in-kernel hypercall if available. The in-kernel
hypercall can be enabled with the use-kvm property, e.g.:
qemu-system-ppc64 -device spapr-rng,use-kvm=true
For handling the hypercall in QEMU instead, a "RngBackend" is
required since the hypercall should provide "good" random data
instead of pseudo-random (like from a "simple" library function
like rand() or g_random_int()). Since there are multiple RngBackends
available, the user must select an appropriate back-end via the
"rng" property of the device, e.g.:
qemu-system-ppc64 -object rng-random,filename=/dev/hwrng,id=gid0 \
-device spapr-rng,rng=gid0 ...
See http://wiki.qemu-project.org/Features-Done/VirtIORNG for
other example of specifying RngBackends.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2015-09-17 11:49:41 +03:00
|
|
|
int kvmppc_enable_hwrng(void)
|
|
|
|
{
|
|
|
|
if (!kvm_enabled() || !kvm_check_extension(kvm_state, KVM_CAP_PPC_HWRNG)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvmppc_enable_hcall(kvm_state, H_RANDOM);
|
|
|
|
}
|
2017-05-12 08:46:11 +03:00
|
|
|
|
|
|
|
void kvmppc_check_papr_resize_hpt(Error **errp)
|
|
|
|
{
|
|
|
|
if (!kvm_enabled()) {
|
2017-07-12 10:56:55 +03:00
|
|
|
return; /* No KVM, we're good */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap_resize_hpt) {
|
|
|
|
return; /* Kernel has explicit support, we're good */
|
2017-05-12 08:46:11 +03:00
|
|
|
}
|
|
|
|
|
2017-07-12 10:56:55 +03:00
|
|
|
/* Otherwise fallback on looking for PR KVM */
|
|
|
|
if (kvmppc_is_pr(kvm_state)) {
|
|
|
|
return;
|
|
|
|
}
|
2017-05-12 08:46:11 +03:00
|
|
|
|
|
|
|
error_setg(errp,
|
|
|
|
"Hash page table resizing not available with this KVM version");
|
|
|
|
}
|
2017-07-12 10:56:55 +03:00
|
|
|
|
|
|
|
int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
struct kvm_ppc_resize_hpt rhpt = {
|
|
|
|
.flags = flags,
|
|
|
|
.shift = shift,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!cap_resize_hpt) {
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_PREPARE, &rhpt);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
struct kvm_ppc_resize_hpt rhpt = {
|
|
|
|
.flags = flags,
|
|
|
|
.shift = shift,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!cap_resize_hpt) {
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_COMMIT, &rhpt);
|
|
|
|
}
|
|
|
|
|
2017-08-09 23:43:46 +03:00
|
|
|
/*
|
|
|
|
* This is a helper function to detect a post migration scenario
|
|
|
|
* in which a guest, running as KVM-HV, freezes in cpu_post_load because
|
|
|
|
* the guest kernel can't handle a PVR value other than the actual host
|
|
|
|
* PVR in KVM_SET_SREGS, even if pvr_match() returns true.
|
|
|
|
*
|
|
|
|
* If we don't have cap_ppc_pvr_compat and we're not running in PR
|
|
|
|
* (so, we're HV), return true. The workaround itself is done in
|
|
|
|
* cpu_post_load.
|
|
|
|
*
|
|
|
|
* The order here is important: we'll only check for KVM PR as a
|
|
|
|
* fallback if the guest kernel can't handle the situation itself.
|
|
|
|
* We need to avoid as much as possible querying the running KVM type
|
|
|
|
* in QEMU level.
|
|
|
|
*/
|
|
|
|
bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
if (!kvm_enabled()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap_ppc_pvr_compat) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !kvmppc_is_pr(cs->kvm_state);
|
|
|
|
}
|
2018-09-04 12:24:18 +03:00
|
|
|
|
|
|
|
void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_ONLINE, &online);
|
|
|
|
}
|
|
|
|
}
|
2019-06-14 14:09:17 +03:00
|
|
|
|
|
|
|
void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset)
|
|
|
|
{
|
|
|
|
CPUState *cs = CPU(cpu);
|
|
|
|
|
|
|
|
if (kvm_enabled()) {
|
|
|
|
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &tb_offset);
|
|
|
|
}
|
|
|
|
}
|
2021-01-26 20:36:47 +03:00
|
|
|
|
|
|
|
bool kvm_arch_cpu_check_are_resettable(void)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2022-09-29 10:20:12 +03:00
|
|
|
|
|
|
|
void kvm_arch_accel_class_init(ObjectClass *oc)
|
|
|
|
{
|
|
|
|
}
|