Here are the 3.13 KVM changes. There was a lot of work on the PPC

side: the HV and emulation flavors can now coexist in a single kernel
 is probably the most interesting change from a user point of view.
 On the x86 side there are nested virtualization improvements and a
 few bugfixes.  ARM got transparent huge page support, improved
 overcommit, and support for big endian guests.
 
 Finally, there is a new interface to connect KVM with VFIO.  This
 helps with devices that use NoSnoop PCI transactions, letting the
 driver in the guest execute WBINVD instructions.  This includes
 some nVidia cards on Windows, that fail to start without these
 patches and the corresponding userspace changes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJShPAhAAoJEBvWZb6bTYbyl48P/297GgmELHAGBgjvb6q7yyGu
 L8+eHjKbh4XBAkPwyzbvUjuww5z2hM0N3JQ0BDV9oeXlO+zwwCEns/sg2Q5/NJXq
 XxnTeShaKnp9lqVBnE6G9rAOUWKoyLJ2wItlvUL8JlaO9xJ0Vmk0ta4n2Nv5GqDp
 db6UD7vju6rHtIAhNpvvAO51kAOwc01xxRixCVb7KUYOnmO9nvpixzoI/S0Rp1gu
 w/OWMfCosDzBoT+cOe79Yx1OKcpaVW94X6CH1s+ShCw3wcbCL2f13Ka8/E3FIcuq
 vkZaLBxio7vjUAHRjPObw0XBW4InXEbhI1DjzIvm8dmc4VsgmtLQkTCG8fj+jINc
 dlHQUq6Do+1F4zy6WMBUj8tNeP1Z9DsABp98rQwR8+BwHoQpGQBpAxW0TE0ZMngC
 t1caqyvjZ5pPpFUxSrAV+8Kg4AvobXPYOim0vqV7Qea07KhFcBXLCfF7BWdwq/Jc
 0CAOlsLL4mHGIQWZJuVGw0YGP7oATDCyewlBuDObx+szYCoV4fQGZVBEL0KwJx/1
 7lrLN7JWzRyw6xTgJ5VVwgYE1tUY4IFQcHu7/5N+dw8/xg9KWA3f4PeMavIKSf+R
 qteewbtmQsxUnvuQIBHLs8NRWPnBPy+F3Sc2ckeOLIe4pmfTte6shtTXcLDL+LqH
 NTmT/cfmYp2BRkiCfCiS
 =rWNf
 -----END PGP SIGNATURE-----

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull KVM changes from Paolo Bonzini:
 "Here are the 3.13 KVM changes.  There was a lot of work on the PPC
  side: the HV and emulation flavors can now coexist in a single kernel
  is probably the most interesting change from a user point of view.

  On the x86 side there are nested virtualization improvements and a few
  bugfixes.

  ARM got transparent huge page support, improved overcommit, and
  support for big endian guests.

  Finally, there is a new interface to connect KVM with VFIO.  This
  helps with devices that use NoSnoop PCI transactions, letting the
  driver in the guest execute WBINVD instructions.  This includes some
  nVidia cards on Windows, that fail to start without these patches and
  the corresponding userspace changes"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (146 commits)
  kvm, vmx: Fix lazy FPU on nested guest
  arm/arm64: KVM: PSCI: propagate caller endianness to the incoming vcpu
  arm/arm64: KVM: MMIO support for BE guest
  kvm, cpuid: Fix sparse warning
  kvm: Delete prototype for non-existent function kvm_check_iopl
  kvm: Delete prototype for non-existent function complete_pio
  hung_task: add method to reset detector
  pvclock: detect watchdog reset at pvclock read
  kvm: optimize out smp_mb after srcu_read_unlock
  srcu: API for barrier after srcu read unlock
  KVM: remove vm mmap method
  KVM: IOMMU: hva align mapping page size
  KVM: x86: trace cpuid emulation when called from emulator
  KVM: emulator: cleanup decode_register_operand() a bit
  KVM: emulator: check rex prefix inside decode_register()
  KVM: x86: fix emulation of "movzbl %bpl, %eax"
  kvm_host: typo fix
  KVM: x86: emulate SAHF instruction
  MAINTAINERS: add tree for kvm.git
  Documentation/kvm: add a 00-INDEX file
  ...
This commit is contained in:
Linus Torvalds 2013-11-15 13:51:36 +09:00
commit f080480488
133 changed files with 5182 additions and 2251 deletions

View file

@ -0,0 +1,24 @@
00-INDEX
- this file.
api.txt
- KVM userspace API.
cpuid.txt
- KVM-specific cpuid leaves (x86).
devices/
- KVM_CAP_DEVICE_CTRL userspace API.
hypercalls.txt
- KVM hypercalls.
locking.txt
- notes on KVM locks.
mmu.txt
- the x86 kvm shadow mmu.
msr.txt
- KVM-specific MSRs (x86).
nested-vmx.txt
- notes on nested virtualization for Intel x86 processors.
ppc-pv.txt
- the paravirtualization interface on PowerPC.
review-checklist.txt
- review checklist for KVM patches.
timekeeping.txt
- timekeeping virtualization for x86-based architectures.

View file

@ -1122,9 +1122,9 @@ struct kvm_cpuid2 {
struct kvm_cpuid_entry2 entries[0]; struct kvm_cpuid_entry2 entries[0];
}; };
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1 #define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0)
#define KVM_CPUID_FLAG_STATEFUL_FUNC 2 #define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1)
#define KVM_CPUID_FLAG_STATE_READ_NEXT 4 #define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2)
struct kvm_cpuid_entry2 { struct kvm_cpuid_entry2 {
__u32 function; __u32 function;
@ -1810,6 +1810,50 @@ registers, find a list below:
PPC | KVM_REG_PPC_TLB3PS | 32 PPC | KVM_REG_PPC_TLB3PS | 32
PPC | KVM_REG_PPC_EPTCFG | 32 PPC | KVM_REG_PPC_EPTCFG | 32
PPC | KVM_REG_PPC_ICP_STATE | 64 PPC | KVM_REG_PPC_ICP_STATE | 64
PPC | KVM_REG_PPC_TB_OFFSET | 64
PPC | KVM_REG_PPC_SPMC1 | 32
PPC | KVM_REG_PPC_SPMC2 | 32
PPC | KVM_REG_PPC_IAMR | 64
PPC | KVM_REG_PPC_TFHAR | 64
PPC | KVM_REG_PPC_TFIAR | 64
PPC | KVM_REG_PPC_TEXASR | 64
PPC | KVM_REG_PPC_FSCR | 64
PPC | KVM_REG_PPC_PSPB | 32
PPC | KVM_REG_PPC_EBBHR | 64
PPC | KVM_REG_PPC_EBBRR | 64
PPC | KVM_REG_PPC_BESCR | 64
PPC | KVM_REG_PPC_TAR | 64
PPC | KVM_REG_PPC_DPDES | 64
PPC | KVM_REG_PPC_DAWR | 64
PPC | KVM_REG_PPC_DAWRX | 64
PPC | KVM_REG_PPC_CIABR | 64
PPC | KVM_REG_PPC_IC | 64
PPC | KVM_REG_PPC_VTB | 64
PPC | KVM_REG_PPC_CSIGR | 64
PPC | KVM_REG_PPC_TACR | 64
PPC | KVM_REG_PPC_TCSCR | 64
PPC | KVM_REG_PPC_PID | 64
PPC | KVM_REG_PPC_ACOP | 64
PPC | KVM_REG_PPC_VRSAVE | 32
PPC | KVM_REG_PPC_LPCR | 64
PPC | KVM_REG_PPC_PPR | 64
PPC | KVM_REG_PPC_ARCH_COMPAT 32
PPC | KVM_REG_PPC_TM_GPR0 | 64
...
PPC | KVM_REG_PPC_TM_GPR31 | 64
PPC | KVM_REG_PPC_TM_VSR0 | 128
...
PPC | KVM_REG_PPC_TM_VSR63 | 128
PPC | KVM_REG_PPC_TM_CR | 64
PPC | KVM_REG_PPC_TM_LR | 64
PPC | KVM_REG_PPC_TM_CTR | 64
PPC | KVM_REG_PPC_TM_FPSCR | 64
PPC | KVM_REG_PPC_TM_AMR | 64
PPC | KVM_REG_PPC_TM_PPR | 64
PPC | KVM_REG_PPC_TM_VRSAVE | 64
PPC | KVM_REG_PPC_TM_VSCR | 32
PPC | KVM_REG_PPC_TM_DSCR | 64
PPC | KVM_REG_PPC_TM_TAR | 64
ARM registers are mapped using the lower 32 bits. The upper 16 of that ARM registers are mapped using the lower 32 bits. The upper 16 of that
is the register group type, or coprocessor number: is the register group type, or coprocessor number:
@ -2304,7 +2348,31 @@ Possible features:
Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only). Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
4.83 KVM_GET_REG_LIST 4.83 KVM_ARM_PREFERRED_TARGET
Capability: basic
Architectures: arm, arm64
Type: vm ioctl
Parameters: struct struct kvm_vcpu_init (out)
Returns: 0 on success; -1 on error
Errors:
ENODEV: no preferred target available for the host
This queries KVM for preferred CPU target type which can be emulated
by KVM on underlying host.
The ioctl returns struct kvm_vcpu_init instance containing information
about preferred CPU target type and recommended features for it. The
kvm_vcpu_init->features bitmap returned will have feature bits set if
the preferred target recommends setting these features, but this is
not mandatory.
The information returned by this ioctl can be used to prepare an instance
of struct kvm_vcpu_init for KVM_ARM_VCPU_INIT ioctl which will result in
in VCPU matching underlying host.
4.84 KVM_GET_REG_LIST
Capability: basic Capability: basic
Architectures: arm, arm64 Architectures: arm, arm64
@ -2323,8 +2391,7 @@ struct kvm_reg_list {
This ioctl returns the guest registers that are supported for the This ioctl returns the guest registers that are supported for the
KVM_GET_ONE_REG/KVM_SET_ONE_REG calls. KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
4.85 KVM_ARM_SET_DEVICE_ADDR
4.84 KVM_ARM_SET_DEVICE_ADDR
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
Architectures: arm, arm64 Architectures: arm, arm64
@ -2362,7 +2429,7 @@ must be called after calling KVM_CREATE_IRQCHIP, but before calling
KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the
base addresses will return -EEXIST. base addresses will return -EEXIST.
4.85 KVM_PPC_RTAS_DEFINE_TOKEN 4.86 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS Capability: KVM_CAP_PPC_RTAS
Architectures: ppc Architectures: ppc
@ -2661,6 +2728,77 @@ and usually define the validity of a groups of registers. (e.g. one bit
}; };
4.81 KVM_GET_EMULATED_CPUID
Capability: KVM_CAP_EXT_EMUL_CPUID
Architectures: x86
Type: system ioctl
Parameters: struct kvm_cpuid2 (in/out)
Returns: 0 on success, -1 on error
struct kvm_cpuid2 {
__u32 nent;
__u32 flags;
struct kvm_cpuid_entry2 entries[0];
};
The member 'flags' is used for passing flags from userspace.
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0)
#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1)
#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2)
struct kvm_cpuid_entry2 {
__u32 function;
__u32 index;
__u32 flags;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding[3];
};
This ioctl returns x86 cpuid features which are emulated by
kvm.Userspace can use the information returned by this ioctl to query
which features are emulated by kvm instead of being present natively.
Userspace invokes KVM_GET_EMULATED_CPUID by passing a kvm_cpuid2
structure with the 'nent' field indicating the number of entries in
the variable-size array 'entries'. If the number of entries is too low
to describe the cpu capabilities, an error (E2BIG) is returned. If the
number is too high, the 'nent' field is adjusted and an error (ENOMEM)
is returned. If the number is just right, the 'nent' field is adjusted
to the number of valid entries in the 'entries' array, which is then
filled.
The entries returned are the set CPUID bits of the respective features
which kvm emulates, as returned by the CPUID instruction, with unknown
or unsupported feature bits cleared.
Features like x2apic, for example, may not be present in the host cpu
but are exposed by kvm in KVM_GET_SUPPORTED_CPUID because they can be
emulated efficiently and thus not included here.
The fields in each entry are defined as follows:
function: the eax value used to obtain the entry
index: the ecx value used to obtain the entry (for entries that are
affected by ecx)
flags: an OR of zero or more of the following:
KVM_CPUID_FLAG_SIGNIFCANT_INDEX:
if the index field is valid
KVM_CPUID_FLAG_STATEFUL_FUNC:
if cpuid for this function returns different values for successive
invocations; there will be several entries with the same function,
all with this flag set
KVM_CPUID_FLAG_STATE_READ_NEXT:
for KVM_CPUID_FLAG_STATEFUL_FUNC entries, set if this entry is
the first entry to be read by a cpu
eax, ebx, ecx, edx: the values returned by the cpuid instruction for
this function/index combination
6. Capabilities that can be enabled 6. Capabilities that can be enabled
----------------------------------- -----------------------------------

View file

@ -43,6 +43,13 @@ KVM_FEATURE_CLOCKSOURCE2 || 3 || kvmclock available at msrs
KVM_FEATURE_ASYNC_PF || 4 || async pf can be enabled by KVM_FEATURE_ASYNC_PF || 4 || async pf can be enabled by
|| || writing to msr 0x4b564d02 || || writing to msr 0x4b564d02
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
KVM_FEATURE_STEAL_TIME || 5 || steal time can be enabled by
|| || writing to msr 0x4b564d03.
------------------------------------------------------------------------------
KVM_FEATURE_PV_EOI || 6 || paravirtualized end of interrupt
|| || handler can be enabled by writing
|| || to msr 0x4b564d04.
------------------------------------------------------------------------------
KVM_FEATURE_PV_UNHALT || 7 || guest checks this feature bit KVM_FEATURE_PV_UNHALT || 7 || guest checks this feature bit
|| || before enabling paravirtualized || || before enabling paravirtualized
|| || spinlock support. || || spinlock support.

View file

@ -0,0 +1,22 @@
VFIO virtual device
===================
Device types supported:
KVM_DEV_TYPE_VFIO
Only one VFIO instance may be created per VM. The created device
tracks VFIO groups in use by the VM and features of those groups
important to the correctness and acceleration of the VM. As groups
are enabled and disabled for use by the VM, KVM should be updated
about their presence. When registered with KVM, a reference to the
VFIO-group is held by KVM.
Groups:
KVM_DEV_VFIO_GROUP
KVM_DEV_VFIO_GROUP attributes:
KVM_DEV_VFIO_GROUP_ADD: Add a VFIO group to VFIO-KVM device tracking
KVM_DEV_VFIO_GROUP_DEL: Remove a VFIO group from VFIO-KVM device tracking
For each, kvm_device_attr.addr points to an int32_t file descriptor
for the VFIO group.

View file

@ -132,10 +132,14 @@ See the comments in spte_has_volatile_bits() and mmu_spte_update().
------------ ------------
Name: kvm_lock Name: kvm_lock
Type: raw_spinlock Type: spinlock_t
Arch: any Arch: any
Protects: - vm_list Protects: - vm_list
- hardware virtualization enable/disable
Name: kvm_count_lock
Type: raw_spinlock_t
Arch: any
Protects: - hardware virtualization enable/disable
Comment: 'raw' because hardware enabling/disabling must be atomic /wrt Comment: 'raw' because hardware enabling/disabling must be atomic /wrt
migration. migration.
@ -151,3 +155,14 @@ Type: spinlock_t
Arch: any Arch: any
Protects: -shadow page/shadow tlb entry Protects: -shadow page/shadow tlb entry
Comment: it is a spinlock since it is used in mmu notifier. Comment: it is a spinlock since it is used in mmu notifier.
Name: kvm->srcu
Type: srcu lock
Arch: any
Protects: - kvm->memslots
- kvm->buses
Comment: The srcu read lock must be held while accessing memslots (e.g.
when using gfn_to_* functions) and while accessing in-kernel
MMIO/PIO address->device structure mapping (kvm->buses).
The srcu index can be stored in kvm_vcpu->srcu_idx per vcpu
if it is needed by multiple functions.

View file

@ -4871,7 +4871,8 @@ KERNEL VIRTUAL MACHINE (KVM)
M: Gleb Natapov <gleb@redhat.com> M: Gleb Natapov <gleb@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
W: http://linux-kvm.org W: http://www.linux-kvm.org
T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git
S: Supported S: Supported
F: Documentation/*/kvm*.txt F: Documentation/*/kvm*.txt
F: Documentation/virtual/kvm/ F: Documentation/virtual/kvm/

View file

@ -57,6 +57,7 @@
* TSC: Trap SMC * TSC: Trap SMC
* TSW: Trap cache operations by set/way * TSW: Trap cache operations by set/way
* TWI: Trap WFI * TWI: Trap WFI
* TWE: Trap WFE
* TIDCP: Trap L2CTLR/L2ECTLR * TIDCP: Trap L2CTLR/L2ECTLR
* BSU_IS: Upgrade barriers to the inner shareable domain * BSU_IS: Upgrade barriers to the inner shareable domain
* FB: Force broadcast of all maintainance operations * FB: Force broadcast of all maintainance operations
@ -67,7 +68,7 @@
*/ */
#define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \ #define HCR_GUEST_MASK (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \ HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
HCR_SWIO | HCR_TIDCP) HCR_TWE | HCR_SWIO | HCR_TIDCP)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
/* System Control Register (SCTLR) bits */ /* System Control Register (SCTLR) bits */
@ -95,12 +96,12 @@
#define TTBCR_IRGN1 (3 << 24) #define TTBCR_IRGN1 (3 << 24)
#define TTBCR_EPD1 (1 << 23) #define TTBCR_EPD1 (1 << 23)
#define TTBCR_A1 (1 << 22) #define TTBCR_A1 (1 << 22)
#define TTBCR_T1SZ (3 << 16) #define TTBCR_T1SZ (7 << 16)
#define TTBCR_SH0 (3 << 12) #define TTBCR_SH0 (3 << 12)
#define TTBCR_ORGN0 (3 << 10) #define TTBCR_ORGN0 (3 << 10)
#define TTBCR_IRGN0 (3 << 8) #define TTBCR_IRGN0 (3 << 8)
#define TTBCR_EPD0 (1 << 7) #define TTBCR_EPD0 (1 << 7)
#define TTBCR_T0SZ 3 #define TTBCR_T0SZ (7 << 0)
#define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0) #define HTCR_MASK (TTBCR_T0SZ | TTBCR_IRGN0 | TTBCR_ORGN0 | TTBCR_SH0)
/* Hyp System Trap Register */ /* Hyp System Trap Register */
@ -208,6 +209,8 @@
#define HSR_EC_DABT (0x24) #define HSR_EC_DABT (0x24)
#define HSR_EC_DABT_HYP (0x25) #define HSR_EC_DABT_HYP (0x25)
#define HSR_WFI_IS_WFE (1U << 0)
#define HSR_HVC_IMM_MASK ((1UL << 16) - 1) #define HSR_HVC_IMM_MASK ((1UL << 16) - 1)
#define HSR_DABT_S1PTW (1U << 7) #define HSR_DABT_S1PTW (1U << 7)

View file

@ -39,7 +39,7 @@
#define c6_IFAR 17 /* Instruction Fault Address Register */ #define c6_IFAR 17 /* Instruction Fault Address Register */
#define c7_PAR 18 /* Physical Address Register */ #define c7_PAR 18 /* Physical Address Register */
#define c7_PAR_high 19 /* PAR top 32 bits */ #define c7_PAR_high 19 /* PAR top 32 bits */
#define c9_L2CTLR 20 /* Cortex A15 L2 Control Register */ #define c9_L2CTLR 20 /* Cortex A15/A7 L2 Control Register */
#define c10_PRRR 21 /* Primary Region Remap Register */ #define c10_PRRR 21 /* Primary Region Remap Register */
#define c10_NMRR 22 /* Normal Memory Remap Register */ #define c10_NMRR 22 /* Normal Memory Remap Register */
#define c12_VBAR 23 /* Vector Base Address Register */ #define c12_VBAR 23 /* Vector Base Address Register */

View file

@ -157,4 +157,55 @@ static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu)
return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK; return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK;
} }
static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu)
{
return vcpu->arch.cp15[c0_MPIDR];
}
static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
{
*vcpu_cpsr(vcpu) |= PSR_E_BIT;
}
static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
{
return !!(*vcpu_cpsr(vcpu) & PSR_E_BIT);
}
static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
{
if (kvm_vcpu_is_be(vcpu)) {
switch (len) {
case 1:
return data & 0xff;
case 2:
return be16_to_cpu(data & 0xffff);
default:
return be32_to_cpu(data);
}
}
return data; /* Leave LE untouched */
}
static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
{
if (kvm_vcpu_is_be(vcpu)) {
switch (len) {
case 1:
return data & 0xff;
case 2:
return cpu_to_be16(data & 0xffff);
default:
return cpu_to_be32(data);
}
}
return data; /* Leave LE untouched */
}
#endif /* __ARM_KVM_EMULATE_H__ */ #endif /* __ARM_KVM_EMULATE_H__ */

View file

@ -38,11 +38,6 @@
#define KVM_VCPU_MAX_FEATURES 1 #define KVM_VCPU_MAX_FEATURES 1
/* We don't currently support large pages. */
#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
#include <kvm/arm_vgic.h> #include <kvm/arm_vgic.h>
struct kvm_vcpu; struct kvm_vcpu;
@ -154,6 +149,7 @@ struct kvm_vcpu_stat {
struct kvm_vcpu_init; struct kvm_vcpu_init;
int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init); const struct kvm_vcpu_init *init);
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
struct kvm_one_reg; struct kvm_one_reg;

View file

@ -62,6 +62,12 @@ phys_addr_t kvm_get_idmap_vector(void);
int kvm_mmu_init(void); int kvm_mmu_init(void);
void kvm_clear_hyp_idmap(void); void kvm_clear_hyp_idmap(void);
static inline void kvm_set_pmd(pmd_t *pmd, pmd_t new_pmd)
{
*pmd = new_pmd;
flush_pmd_entry(pmd);
}
static inline void kvm_set_pte(pte_t *pte, pte_t new_pte) static inline void kvm_set_pte(pte_t *pte, pte_t new_pte)
{ {
*pte = new_pte; *pte = new_pte;
@ -103,9 +109,15 @@ static inline void kvm_set_s2pte_writable(pte_t *pte)
pte_val(*pte) |= L_PTE_S2_RDWR; pte_val(*pte) |= L_PTE_S2_RDWR;
} }
static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
{
pmd_val(*pmd) |= L_PMD_S2_RDWR;
}
struct kvm; struct kvm;
static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
unsigned long size)
{ {
/* /*
* If we are going to insert an instruction page and the icache is * If we are going to insert an instruction page and the icache is
@ -120,8 +132,7 @@ static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
* need any kind of flushing (DDI 0406C.b - Page B3-1392). * need any kind of flushing (DDI 0406C.b - Page B3-1392).
*/ */
if (icache_is_pipt()) { if (icache_is_pipt()) {
unsigned long hva = gfn_to_hva(kvm, gfn); __cpuc_coherent_user_range(hva, hva + size);
__cpuc_coherent_user_range(hva, hva + PAGE_SIZE);
} else if (!icache_is_vivt_asid_tagged()) { } else if (!icache_is_vivt_asid_tagged()) {
/* any kind of VIPT cache */ /* any kind of VIPT cache */
__flush_icache_all(); __flush_icache_all();

View file

@ -126,6 +126,8 @@
#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */ #define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ #define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
#define L_PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
/* /*
* Hyp-mode PL2 PTE definitions for LPAE. * Hyp-mode PL2 PTE definitions for LPAE.
*/ */

View file

@ -63,7 +63,8 @@ struct kvm_regs {
/* Supported Processor Types */ /* Supported Processor Types */
#define KVM_ARM_TARGET_CORTEX_A15 0 #define KVM_ARM_TARGET_CORTEX_A15 0
#define KVM_ARM_NUM_TARGETS 1 #define KVM_ARM_TARGET_CORTEX_A7 1
#define KVM_ARM_NUM_TARGETS 2
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
#define KVM_ARM_DEVICE_TYPE_SHIFT 0 #define KVM_ARM_DEVICE_TYPE_SHIFT 0

View file

@ -20,6 +20,7 @@ config KVM
bool "Kernel-based Virtual Machine (KVM) support" bool "Kernel-based Virtual Machine (KVM) support"
select PREEMPT_NOTIFIERS select PREEMPT_NOTIFIERS
select ANON_INODES select ANON_INODES
select HAVE_KVM_CPU_RELAX_INTERCEPT
select KVM_MMIO select KVM_MMIO
select KVM_ARM_HOST select KVM_ARM_HOST
depends on ARM_VIRT_EXT && ARM_LPAE depends on ARM_VIRT_EXT && ARM_LPAE

View file

@ -19,6 +19,6 @@ kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o
obj-y += kvm-arm.o init.o interrupts.o obj-y += kvm-arm.o init.o interrupts.o
obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o

View file

@ -152,12 +152,13 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
return VM_FAULT_SIGBUS; return VM_FAULT_SIGBUS;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free, void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
} }
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages)
{ {
return 0; return 0;
} }
@ -797,6 +798,19 @@ long kvm_arch_vm_ioctl(struct file *filp,
return -EFAULT; return -EFAULT;
return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr); return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr);
} }
case KVM_ARM_PREFERRED_TARGET: {
int err;
struct kvm_vcpu_init init;
err = kvm_vcpu_preferred_target(&init);
if (err)
return err;
if (copy_to_user(argp, &init, sizeof(init)))
return -EFAULT;
return 0;
}
default: default:
return -EINVAL; return -EINVAL;
} }

View file

@ -71,6 +71,98 @@ int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
return 1; return 1;
} }
static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
/*
* Compute guest MPIDR. We build a virtual cluster out of the
* vcpu_id, but we read the 'U' bit from the underlying
* hardware directly.
*/
vcpu->arch.cp15[c0_MPIDR] = ((read_cpuid_mpidr() & MPIDR_SMP_BITMASK) |
((vcpu->vcpu_id >> 2) << MPIDR_LEVEL_BITS) |
(vcpu->vcpu_id & 3));
}
/* TRM entries A7:4.3.31 A15:4.3.28 - RO WI */
static bool access_actlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
return true;
}
/* TRM entries A7:4.3.56, A15:4.3.60 - R/O. */
static bool access_cbar(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return write_to_read_only(vcpu, p);
return read_zero(vcpu, p);
}
/* TRM entries A7:4.3.49, A15:4.3.48 - R/O WI */
static bool access_l2ctlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
return true;
}
static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
u32 l2ctlr, ncores;
asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
l2ctlr &= ~(3 << 24);
ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
/* How many cores in the current cluster and the next ones */
ncores -= (vcpu->vcpu_id & ~3);
/* Cap it to the maximum number of cores in a single cluster */
ncores = min(ncores, 3U);
l2ctlr |= (ncores & 3) << 24;
vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
}
static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
u32 actlr;
/* ACTLR contains SMP bit: make sure you create all cpus first! */
asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
/* Make the SMP bit consistent with the guest configuration */
if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
actlr |= 1U << 6;
else
actlr &= ~(1U << 6);
vcpu->arch.cp15[c1_ACTLR] = actlr;
}
/*
* TRM entries: A7:4.3.50, A15:4.3.49
* R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored).
*/
static bool access_l2ectlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = 0;
return true;
}
/* See note at ARM ARM B1.14.4 */ /* See note at ARM ARM B1.14.4 */
static bool access_dcsw(struct kvm_vcpu *vcpu, static bool access_dcsw(struct kvm_vcpu *vcpu,
const struct coproc_params *p, const struct coproc_params *p,
@ -153,10 +245,22 @@ static bool pm_fake(struct kvm_vcpu *vcpu,
* registers preceding 32-bit ones. * registers preceding 32-bit ones.
*/ */
static const struct coproc_reg cp15_regs[] = { static const struct coproc_reg cp15_regs[] = {
/* MPIDR: we use VMPIDR for guest access. */
{ CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
NULL, reset_mpidr, c0_MPIDR },
/* CSSELR: swapped by interrupt.S. */ /* CSSELR: swapped by interrupt.S. */
{ CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32, { CRn( 0), CRm( 0), Op1( 2), Op2( 0), is32,
NULL, reset_unknown, c0_CSSELR }, NULL, reset_unknown, c0_CSSELR },
/* ACTLR: trapped by HCR.TAC bit. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
access_actlr, reset_actlr, c1_ACTLR },
/* CPACR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_val, c1_CPACR, 0x00000000 },
/* TTBR0/TTBR1: swapped by interrupt.S. */ /* TTBR0/TTBR1: swapped by interrupt.S. */
{ CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 }, { CRm64( 2), Op1( 0), is64, NULL, reset_unknown64, c2_TTBR0 },
{ CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 }, { CRm64( 2), Op1( 1), is64, NULL, reset_unknown64, c2_TTBR1 },
@ -194,6 +298,13 @@ static const struct coproc_reg cp15_regs[] = {
{ CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw}, { CRn( 7), CRm( 6), Op1( 0), Op2( 2), is32, access_dcsw},
{ CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw}, { CRn( 7), CRm(10), Op1( 0), Op2( 2), is32, access_dcsw},
{ CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw}, { CRn( 7), CRm(14), Op1( 0), Op2( 2), is32, access_dcsw},
/*
* L2CTLR access (guest wants to know #CPUs).
*/
{ CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
{ CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
/* /*
* Dummy performance monitor implementation. * Dummy performance monitor implementation.
*/ */
@ -234,6 +345,9 @@ static const struct coproc_reg cp15_regs[] = {
/* CNTKCTL: swapped by interrupt.S. */ /* CNTKCTL: swapped by interrupt.S. */
{ CRn(14), CRm( 1), Op1( 0), Op2( 0), is32, { CRn(14), CRm( 1), Op1( 0), Op2( 0), is32,
NULL, reset_val, c14_CNTKCTL, 0x00000000 }, NULL, reset_val, c14_CNTKCTL, 0x00000000 },
/* The Configuration Base Address Register. */
{ CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
}; };
/* Target specific emulation tables */ /* Target specific emulation tables */
@ -241,6 +355,12 @@ static struct kvm_coproc_target_table *target_tables[KVM_ARM_NUM_TARGETS];
void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table) void kvm_register_target_coproc_table(struct kvm_coproc_target_table *table)
{ {
unsigned int i;
for (i = 1; i < table->num; i++)
BUG_ON(cmp_reg(&table->table[i-1],
&table->table[i]) >= 0);
target_tables[table->target] = table; target_tables[table->target] = table;
} }

View file

@ -17,101 +17,12 @@
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <asm/cputype.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_host.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h> #include <asm/kvm_coproc.h>
#include <asm/kvm_emulate.h>
#include <linux/init.h> #include <linux/init.h>
static void reset_mpidr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
/*
* Compute guest MPIDR:
* (Even if we present only one VCPU to the guest on an SMP
* host we don't set the U bit in the MPIDR, or vice versa, as
* revealing the underlying hardware properties is likely to
* be the best choice).
*/
vcpu->arch.cp15[c0_MPIDR] = (read_cpuid_mpidr() & ~MPIDR_LEVEL_MASK)
| (vcpu->vcpu_id & MPIDR_LEVEL_MASK);
}
#include "coproc.h" #include "coproc.h"
/* A15 TRM 4.3.28: RO WI */
static bool access_actlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c1_ACTLR];
return true;
}
/* A15 TRM 4.3.60: R/O. */
static bool access_cbar(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return write_to_read_only(vcpu, p);
return read_zero(vcpu, p);
}
/* A15 TRM 4.3.48: R/O WI. */
static bool access_l2ctlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = vcpu->arch.cp15[c9_L2CTLR];
return true;
}
static void reset_l2ctlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
u32 l2ctlr, ncores;
asm volatile("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
l2ctlr &= ~(3 << 24);
ncores = atomic_read(&vcpu->kvm->online_vcpus) - 1;
l2ctlr |= (ncores & 3) << 24;
vcpu->arch.cp15[c9_L2CTLR] = l2ctlr;
}
static void reset_actlr(struct kvm_vcpu *vcpu, const struct coproc_reg *r)
{
u32 actlr;
/* ACTLR contains SMP bit: make sure you create all cpus first! */
asm volatile("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
/* Make the SMP bit consistent with the guest configuration */
if (atomic_read(&vcpu->kvm->online_vcpus) > 1)
actlr |= 1U << 6;
else
actlr &= ~(1U << 6);
vcpu->arch.cp15[c1_ACTLR] = actlr;
}
/* A15 TRM 4.3.49: R/O WI (even if NSACR.NS_L2ERR, a write of 1 is ignored). */
static bool access_l2ectlr(struct kvm_vcpu *vcpu,
const struct coproc_params *p,
const struct coproc_reg *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
*vcpu_reg(vcpu, p->Rt1) = 0;
return true;
}
/* /*
* A15-specific CP15 registers. * A15-specific CP15 registers.
* CRn denotes the primary register number, but is copied to the CRm in the * CRn denotes the primary register number, but is copied to the CRm in the
@ -121,29 +32,9 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
* registers preceding 32-bit ones. * registers preceding 32-bit ones.
*/ */
static const struct coproc_reg a15_regs[] = { static const struct coproc_reg a15_regs[] = {
/* MPIDR: we use VMPIDR for guest access. */
{ CRn( 0), CRm( 0), Op1( 0), Op2( 5), is32,
NULL, reset_mpidr, c0_MPIDR },
/* SCTLR: swapped by interrupt.S. */ /* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32, { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
NULL, reset_val, c1_SCTLR, 0x00C50078 }, NULL, reset_val, c1_SCTLR, 0x00C50078 },
/* ACTLR: trapped by HCR.TAC bit. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 1), is32,
access_actlr, reset_actlr, c1_ACTLR },
/* CPACR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_val, c1_CPACR, 0x00000000 },
/*
* L2CTLR access (guest wants to know #CPUs).
*/
{ CRn( 9), CRm( 0), Op1( 1), Op2( 2), is32,
access_l2ctlr, reset_l2ctlr, c9_L2CTLR },
{ CRn( 9), CRm( 0), Op1( 1), Op2( 3), is32, access_l2ectlr},
/* The Configuration Base Address Register. */
{ CRn(15), CRm( 0), Op1( 4), Op2( 0), is32, access_cbar},
}; };
static struct kvm_coproc_target_table a15_target_table = { static struct kvm_coproc_target_table a15_target_table = {
@ -154,12 +45,6 @@ static struct kvm_coproc_target_table a15_target_table = {
static int __init coproc_a15_init(void) static int __init coproc_a15_init(void)
{ {
unsigned int i;
for (i = 1; i < ARRAY_SIZE(a15_regs); i++)
BUG_ON(cmp_reg(&a15_regs[i-1],
&a15_regs[i]) >= 0);
kvm_register_target_coproc_table(&a15_target_table); kvm_register_target_coproc_table(&a15_target_table);
return 0; return 0;
} }

54
arch/arm/kvm/coproc_a7.c Normal file
View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2012 - Virtual Open Systems and Columbia University
* Copyright (C) 2013 - ARM Ltd
*
* Authors: Rusty Russell <rusty@rustcorp.au>
* Christoffer Dall <c.dall@virtualopensystems.com>
* Jonathan Austin <jonathan.austin@arm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/kvm_host.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_emulate.h>
#include <linux/init.h>
#include "coproc.h"
/*
* Cortex-A7 specific CP15 registers.
* CRn denotes the primary register number, but is copied to the CRm in the
* user space API for 64-bit register access in line with the terminology used
* in the ARM ARM.
* Important: Must be sorted ascending by CRn, CRM, Op1, Op2 and with 64-bit
* registers preceding 32-bit ones.
*/
static const struct coproc_reg a7_regs[] = {
/* SCTLR: swapped by interrupt.S. */
{ CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
NULL, reset_val, c1_SCTLR, 0x00C50878 },
};
static struct kvm_coproc_target_table a7_target_table = {
.target = KVM_ARM_TARGET_CORTEX_A7,
.table = a7_regs,
.num = ARRAY_SIZE(a7_regs),
};
static int __init coproc_a7_init(void)
{
kvm_register_target_coproc_table(&a7_target_table);
return 0;
}
late_initcall(coproc_a7_init);

View file

@ -354,7 +354,7 @@ static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset; *vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
if (is_pabt) { if (is_pabt) {
/* Set DFAR and DFSR */ /* Set IFAR and IFSR */
vcpu->arch.cp15[c6_IFAR] = addr; vcpu->arch.cp15[c6_IFAR] = addr;
is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31); is_lpae = (vcpu->arch.cp15[c2_TTBCR] >> 31);
/* Always give debug fault for now - should give guest a clue */ /* Always give debug fault for now - should give guest a clue */

View file

@ -190,6 +190,8 @@ int __attribute_const__ kvm_target_cpu(void)
return -EINVAL; return -EINVAL;
switch (part_number) { switch (part_number) {
case ARM_CPU_PART_CORTEX_A7:
return KVM_ARM_TARGET_CORTEX_A7;
case ARM_CPU_PART_CORTEX_A15: case ARM_CPU_PART_CORTEX_A15:
return KVM_ARM_TARGET_CORTEX_A15; return KVM_ARM_TARGET_CORTEX_A15;
default: default:
@ -202,7 +204,7 @@ int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
{ {
unsigned int i; unsigned int i;
/* We can only do a cortex A15 for now. */ /* We can only cope with guest==host and only on A15/A7 (for now). */
if (init->target != kvm_target_cpu()) if (init->target != kvm_target_cpu())
return -EINVAL; return -EINVAL;
@ -222,6 +224,26 @@ int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
return kvm_reset_vcpu(vcpu); return kvm_reset_vcpu(vcpu);
} }
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
{
int target = kvm_target_cpu();
if (target < 0)
return -ENODEV;
memset(init, 0, sizeof(*init));
/*
* For now, we don't return any features.
* In future, we might use features to return target
* specific features available for the preferred
* target type.
*/
init->target = (__u32)target;
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{ {
return -EINVAL; return -EINVAL;

View file

@ -73,23 +73,29 @@ static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
} }
/** /**
* kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest * kvm_handle_wfx - handle a WFI or WFE instructions trapped in guests
* @vcpu: the vcpu pointer * @vcpu: the vcpu pointer
* @run: the kvm_run structure pointer * @run: the kvm_run structure pointer
* *
* Simply sets the wait_for_interrupts flag on the vcpu structure, which will * WFE: Yield the CPU and come back to this vcpu when the scheduler
* halt execution of world-switches and schedule other host processes until * decides to.
* there is an incoming IRQ or FIQ to the VM. * WFI: Simply call kvm_vcpu_block(), which will halt execution of
* world-switches and schedule other host processes until there is an
* incoming IRQ or FIQ to the VM.
*/ */
static int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run) static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
trace_kvm_wfi(*vcpu_pc(vcpu)); trace_kvm_wfi(*vcpu_pc(vcpu));
kvm_vcpu_block(vcpu); if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE)
kvm_vcpu_on_spin(vcpu);
else
kvm_vcpu_block(vcpu);
return 1; return 1;
} }
static exit_handle_fn arm_exit_handlers[] = { static exit_handle_fn arm_exit_handlers[] = {
[HSR_EC_WFI] = kvm_handle_wfi, [HSR_EC_WFI] = kvm_handle_wfx,
[HSR_EC_CP15_32] = kvm_handle_cp15_32, [HSR_EC_CP15_32] = kvm_handle_cp15_32,
[HSR_EC_CP15_64] = kvm_handle_cp15_64, [HSR_EC_CP15_64] = kvm_handle_cp15_64,
[HSR_EC_CP14_MR] = kvm_handle_cp14_access, [HSR_EC_CP14_MR] = kvm_handle_cp14_access,

View file

@ -23,6 +23,68 @@
#include "trace.h" #include "trace.h"
static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
{
void *datap = NULL;
union {
u8 byte;
u16 hword;
u32 word;
u64 dword;
} tmp;
switch (len) {
case 1:
tmp.byte = data;
datap = &tmp.byte;
break;
case 2:
tmp.hword = data;
datap = &tmp.hword;
break;
case 4:
tmp.word = data;
datap = &tmp.word;
break;
case 8:
tmp.dword = data;
datap = &tmp.dword;
break;
}
memcpy(buf, datap, len);
}
static unsigned long mmio_read_buf(char *buf, unsigned int len)
{
unsigned long data = 0;
union {
u16 hword;
u32 word;
u64 dword;
} tmp;
switch (len) {
case 1:
data = buf[0];
break;
case 2:
memcpy(&tmp.hword, buf, len);
data = tmp.hword;
break;
case 4:
memcpy(&tmp.word, buf, len);
data = tmp.word;
break;
case 8:
memcpy(&tmp.dword, buf, len);
data = tmp.dword;
break;
}
return data;
}
/** /**
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
* @vcpu: The VCPU pointer * @vcpu: The VCPU pointer
@ -33,28 +95,27 @@
*/ */
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
unsigned long *dest; unsigned long data;
unsigned int len; unsigned int len;
int mask; int mask;
if (!run->mmio.is_write) { if (!run->mmio.is_write) {
dest = vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt);
*dest = 0;
len = run->mmio.len; len = run->mmio.len;
if (len > sizeof(unsigned long)) if (len > sizeof(unsigned long))
return -EINVAL; return -EINVAL;
memcpy(dest, run->mmio.data, len); data = mmio_read_buf(run->mmio.data, len);
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
*((u64 *)run->mmio.data));
if (vcpu->arch.mmio_decode.sign_extend && if (vcpu->arch.mmio_decode.sign_extend &&
len < sizeof(unsigned long)) { len < sizeof(unsigned long)) {
mask = 1U << ((len * 8) - 1); mask = 1U << ((len * 8) - 1);
*dest = (*dest ^ mask) - mask; data = (data ^ mask) - mask;
} }
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
data);
data = vcpu_data_host_to_guest(vcpu, data, len);
*vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data;
} }
return 0; return 0;
@ -105,6 +166,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
phys_addr_t fault_ipa) phys_addr_t fault_ipa)
{ {
struct kvm_exit_mmio mmio; struct kvm_exit_mmio mmio;
unsigned long data;
unsigned long rt; unsigned long rt;
int ret; int ret;
@ -125,13 +187,15 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
} }
rt = vcpu->arch.mmio_decode.rt; rt = vcpu->arch.mmio_decode.rt;
data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), mmio.len);
trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE : trace_kvm_mmio((mmio.is_write) ? KVM_TRACE_MMIO_WRITE :
KVM_TRACE_MMIO_READ_UNSATISFIED, KVM_TRACE_MMIO_READ_UNSATISFIED,
mmio.len, fault_ipa, mmio.len, fault_ipa,
(mmio.is_write) ? *vcpu_reg(vcpu, rt) : 0); (mmio.is_write) ? data : 0);
if (mmio.is_write) if (mmio.is_write)
memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len); mmio_write_buf(mmio.data, mmio.len, data);
if (vgic_handle_mmio(vcpu, run, &mmio)) if (vgic_handle_mmio(vcpu, run, &mmio))
return 1; return 1;

View file

@ -19,6 +19,7 @@
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/hugetlb.h>
#include <trace/events/kvm.h> #include <trace/events/kvm.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
@ -41,6 +42,8 @@ static unsigned long hyp_idmap_start;
static unsigned long hyp_idmap_end; static unsigned long hyp_idmap_end;
static phys_addr_t hyp_idmap_vector; static phys_addr_t hyp_idmap_vector;
#define kvm_pmd_huge(_x) (pmd_huge(_x) || pmd_trans_huge(_x))
static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
{ {
/* /*
@ -93,19 +96,29 @@ static bool page_empty(void *ptr)
static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr) static void clear_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
{ {
pmd_t *pmd_table = pmd_offset(pud, 0); if (pud_huge(*pud)) {
pud_clear(pud); pud_clear(pud);
kvm_tlb_flush_vmid_ipa(kvm, addr); kvm_tlb_flush_vmid_ipa(kvm, addr);
pmd_free(NULL, pmd_table); } else {
pmd_t *pmd_table = pmd_offset(pud, 0);
pud_clear(pud);
kvm_tlb_flush_vmid_ipa(kvm, addr);
pmd_free(NULL, pmd_table);
}
put_page(virt_to_page(pud)); put_page(virt_to_page(pud));
} }
static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr) static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
{ {
pte_t *pte_table = pte_offset_kernel(pmd, 0); if (kvm_pmd_huge(*pmd)) {
pmd_clear(pmd); pmd_clear(pmd);
kvm_tlb_flush_vmid_ipa(kvm, addr); kvm_tlb_flush_vmid_ipa(kvm, addr);
pte_free_kernel(NULL, pte_table); } else {
pte_t *pte_table = pte_offset_kernel(pmd, 0);
pmd_clear(pmd);
kvm_tlb_flush_vmid_ipa(kvm, addr);
pte_free_kernel(NULL, pte_table);
}
put_page(virt_to_page(pmd)); put_page(virt_to_page(pmd));
} }
@ -136,18 +149,32 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp,
continue; continue;
} }
if (pud_huge(*pud)) {
/*
* If we are dealing with a huge pud, just clear it and
* move on.
*/
clear_pud_entry(kvm, pud, addr);
addr = pud_addr_end(addr, end);
continue;
}
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd)) { if (pmd_none(*pmd)) {
addr = pmd_addr_end(addr, end); addr = pmd_addr_end(addr, end);
continue; continue;
} }
pte = pte_offset_kernel(pmd, addr); if (!kvm_pmd_huge(*pmd)) {
clear_pte_entry(kvm, pte, addr); pte = pte_offset_kernel(pmd, addr);
next = addr + PAGE_SIZE; clear_pte_entry(kvm, pte, addr);
next = addr + PAGE_SIZE;
}
/* If we emptied the pte, walk back up the ladder */ /*
if (page_empty(pte)) { * If the pmd entry is to be cleared, walk back up the ladder
*/
if (kvm_pmd_huge(*pmd) || page_empty(pte)) {
clear_pmd_entry(kvm, pmd, addr); clear_pmd_entry(kvm, pmd, addr);
next = pmd_addr_end(addr, end); next = pmd_addr_end(addr, end);
if (page_empty(pmd) && !page_empty(pud)) { if (page_empty(pmd) && !page_empty(pud)) {
@ -420,29 +447,71 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
kvm->arch.pgd = NULL; kvm->arch.pgd = NULL;
} }
static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, phys_addr_t addr)
phys_addr_t addr, const pte_t *new_pte, bool iomap)
{ {
pgd_t *pgd; pgd_t *pgd;
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte, old_pte;
/* Create 2nd stage page table mapping - Level 1 */
pgd = kvm->arch.pgd + pgd_index(addr); pgd = kvm->arch.pgd + pgd_index(addr);
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
if (pud_none(*pud)) { if (pud_none(*pud)) {
if (!cache) if (!cache)
return 0; /* ignore calls from kvm_set_spte_hva */ return NULL;
pmd = mmu_memory_cache_alloc(cache); pmd = mmu_memory_cache_alloc(cache);
pud_populate(NULL, pud, pmd); pud_populate(NULL, pud, pmd);
get_page(virt_to_page(pud)); get_page(virt_to_page(pud));
} }
pmd = pmd_offset(pud, addr); return pmd_offset(pud, addr);
}
/* Create 2nd stage page table mapping - Level 2 */ static int stage2_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
*cache, phys_addr_t addr, const pmd_t *new_pmd)
{
pmd_t *pmd, old_pmd;
pmd = stage2_get_pmd(kvm, cache, addr);
VM_BUG_ON(!pmd);
/*
* Mapping in huge pages should only happen through a fault. If a
* page is merged into a transparent huge page, the individual
* subpages of that huge page should be unmapped through MMU
* notifiers before we get here.
*
* Merging of CompoundPages is not supported; they should become
* splitting first, unmapped, merged, and mapped back in on-demand.
*/
VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd));
old_pmd = *pmd;
kvm_set_pmd(pmd, *new_pmd);
if (pmd_present(old_pmd))
kvm_tlb_flush_vmid_ipa(kvm, addr);
else
get_page(virt_to_page(pmd));
return 0;
}
static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
phys_addr_t addr, const pte_t *new_pte, bool iomap)
{
pmd_t *pmd;
pte_t *pte, old_pte;
/* Create stage-2 page table mapping - Level 1 */
pmd = stage2_get_pmd(kvm, cache, addr);
if (!pmd) {
/*
* Ignore calls from kvm_set_spte_hva for unallocated
* address ranges.
*/
return 0;
}
/* Create stage-2 page mappings - Level 2 */
if (pmd_none(*pmd)) { if (pmd_none(*pmd)) {
if (!cache) if (!cache)
return 0; /* ignore calls from kvm_set_spte_hva */ return 0; /* ignore calls from kvm_set_spte_hva */
@ -507,16 +576,60 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
return ret; return ret;
} }
static bool transparent_hugepage_adjust(pfn_t *pfnp, phys_addr_t *ipap)
{
pfn_t pfn = *pfnp;
gfn_t gfn = *ipap >> PAGE_SHIFT;
if (PageTransCompound(pfn_to_page(pfn))) {
unsigned long mask;
/*
* The address we faulted on is backed by a transparent huge
* page. However, because we map the compound huge page and
* not the individual tail page, we need to transfer the
* refcount to the head page. We have to be careful that the
* THP doesn't start to split while we are adjusting the
* refcounts.
*
* We are sure this doesn't happen, because mmu_notifier_retry
* was successful and we are holding the mmu_lock, so if this
* THP is trying to split, it will be blocked in the mmu
* notifier before touching any of the pages, specifically
* before being able to call __split_huge_page_refcount().
*
* We can therefore safely transfer the refcount from PG_tail
* to PG_head and switch the pfn from a tail page to the head
* page accordingly.
*/
mask = PTRS_PER_PMD - 1;
VM_BUG_ON((gfn & mask) != (pfn & mask));
if (pfn & mask) {
*ipap &= PMD_MASK;
kvm_release_pfn_clean(pfn);
pfn &= ~mask;
kvm_get_pfn(pfn);
*pfnp = pfn;
}
return true;
}
return false;
}
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
gfn_t gfn, struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
unsigned long fault_status) unsigned long fault_status)
{ {
pte_t new_pte;
pfn_t pfn;
int ret; int ret;
bool write_fault, writable; bool write_fault, writable, hugetlb = false, force_pte = false;
unsigned long mmu_seq; unsigned long mmu_seq;
gfn_t gfn = fault_ipa >> PAGE_SHIFT;
unsigned long hva = gfn_to_hva(vcpu->kvm, gfn);
struct kvm *kvm = vcpu->kvm;
struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
struct vm_area_struct *vma;
pfn_t pfn;
write_fault = kvm_is_write_fault(kvm_vcpu_get_hsr(vcpu)); write_fault = kvm_is_write_fault(kvm_vcpu_get_hsr(vcpu));
if (fault_status == FSC_PERM && !write_fault) { if (fault_status == FSC_PERM && !write_fault) {
@ -524,6 +637,26 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
return -EFAULT; return -EFAULT;
} }
/* Let's check if we will get back a huge page backed by hugetlbfs */
down_read(&current->mm->mmap_sem);
vma = find_vma_intersection(current->mm, hva, hva + 1);
if (is_vm_hugetlb_page(vma)) {
hugetlb = true;
gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
} else {
/*
* Pages belonging to VMAs not aligned to the PMD mapping
* granularity cannot be mapped using block descriptors even
* if the pages belong to a THP for the process, because the
* stage-2 block descriptor will cover more than a single THP
* and we loose atomicity for unmapping, updates, and splits
* of the THP or other pages in the stage-2 block range.
*/
if (vma->vm_start & ~PMD_MASK)
force_pte = true;
}
up_read(&current->mm->mmap_sem);
/* We need minimum second+third level pages */ /* We need minimum second+third level pages */
ret = mmu_topup_memory_cache(memcache, 2, KVM_NR_MEM_OBJS); ret = mmu_topup_memory_cache(memcache, 2, KVM_NR_MEM_OBJS);
if (ret) if (ret)
@ -541,26 +674,40 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
*/ */
smp_rmb(); smp_rmb();
pfn = gfn_to_pfn_prot(vcpu->kvm, gfn, write_fault, &writable); pfn = gfn_to_pfn_prot(kvm, gfn, write_fault, &writable);
if (is_error_pfn(pfn)) if (is_error_pfn(pfn))
return -EFAULT; return -EFAULT;
new_pte = pfn_pte(pfn, PAGE_S2); spin_lock(&kvm->mmu_lock);
coherent_icache_guest_page(vcpu->kvm, gfn); if (mmu_notifier_retry(kvm, mmu_seq))
spin_lock(&vcpu->kvm->mmu_lock);
if (mmu_notifier_retry(vcpu->kvm, mmu_seq))
goto out_unlock; goto out_unlock;
if (writable) { if (!hugetlb && !force_pte)
kvm_set_s2pte_writable(&new_pte); hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
kvm_set_pfn_dirty(pfn);
if (hugetlb) {
pmd_t new_pmd = pfn_pmd(pfn, PAGE_S2);
new_pmd = pmd_mkhuge(new_pmd);
if (writable) {
kvm_set_s2pmd_writable(&new_pmd);
kvm_set_pfn_dirty(pfn);
}
coherent_icache_guest_page(kvm, hva & PMD_MASK, PMD_SIZE);
ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
} else {
pte_t new_pte = pfn_pte(pfn, PAGE_S2);
if (writable) {
kvm_set_s2pte_writable(&new_pte);
kvm_set_pfn_dirty(pfn);
}
coherent_icache_guest_page(kvm, hva, PAGE_SIZE);
ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, false);
} }
stage2_set_pte(vcpu->kvm, memcache, fault_ipa, &new_pte, false);
out_unlock: out_unlock:
spin_unlock(&vcpu->kvm->mmu_lock); spin_unlock(&kvm->mmu_lock);
kvm_release_pfn_clean(pfn); kvm_release_pfn_clean(pfn);
return 0; return ret;
} }
/** /**
@ -629,7 +776,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
memslot = gfn_to_memslot(vcpu->kvm, gfn); memslot = gfn_to_memslot(vcpu->kvm, gfn);
ret = user_mem_abort(vcpu, fault_ipa, gfn, memslot, fault_status); ret = user_mem_abort(vcpu, fault_ipa, memslot, fault_status);
if (ret == 0) if (ret == 0)
ret = 1; ret = 1;
out_unlock: out_unlock:

View file

@ -18,6 +18,7 @@
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <asm/cputype.h>
#include <asm/kvm_emulate.h> #include <asm/kvm_emulate.h>
#include <asm/kvm_psci.h> #include <asm/kvm_psci.h>
@ -34,22 +35,30 @@ static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
{ {
struct kvm *kvm = source_vcpu->kvm; struct kvm *kvm = source_vcpu->kvm;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu = NULL, *tmp;
wait_queue_head_t *wq; wait_queue_head_t *wq;
unsigned long cpu_id; unsigned long cpu_id;
unsigned long mpidr;
phys_addr_t target_pc; phys_addr_t target_pc;
int i;
cpu_id = *vcpu_reg(source_vcpu, 1); cpu_id = *vcpu_reg(source_vcpu, 1);
if (vcpu_mode_is_32bit(source_vcpu)) if (vcpu_mode_is_32bit(source_vcpu))
cpu_id &= ~((u32) 0); cpu_id &= ~((u32) 0);
if (cpu_id >= atomic_read(&kvm->online_vcpus)) kvm_for_each_vcpu(i, tmp, kvm) {
mpidr = kvm_vcpu_get_mpidr(tmp);
if ((mpidr & MPIDR_HWID_BITMASK) == (cpu_id & MPIDR_HWID_BITMASK)) {
vcpu = tmp;
break;
}
}
if (!vcpu)
return KVM_PSCI_RET_INVAL; return KVM_PSCI_RET_INVAL;
target_pc = *vcpu_reg(source_vcpu, 2); target_pc = *vcpu_reg(source_vcpu, 2);
vcpu = kvm_get_vcpu(kvm, cpu_id);
wq = kvm_arch_vcpu_wq(vcpu); wq = kvm_arch_vcpu_wq(vcpu);
if (!waitqueue_active(wq)) if (!waitqueue_active(wq))
return KVM_PSCI_RET_INVAL; return KVM_PSCI_RET_INVAL;
@ -62,6 +71,10 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
vcpu_set_thumb(vcpu); vcpu_set_thumb(vcpu);
} }
/* Propagate caller endianness */
if (kvm_vcpu_is_be(source_vcpu))
kvm_vcpu_set_be(vcpu);
*vcpu_pc(vcpu) = target_pc; *vcpu_pc(vcpu) = target_pc;
vcpu->arch.pause = false; vcpu->arch.pause = false;
smp_mb(); /* Make sure the above is visible */ smp_mb(); /* Make sure the above is visible */

View file

@ -30,16 +30,14 @@
#include <kvm/arm_arch_timer.h> #include <kvm/arm_arch_timer.h>
/****************************************************************************** /******************************************************************************
* Cortex-A15 Reset Values * Cortex-A15 and Cortex-A7 Reset Values
*/ */
static const int a15_max_cpu_idx = 3; static struct kvm_regs cortexa_regs_reset = {
static struct kvm_regs a15_regs_reset = {
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT, .usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
}; };
static const struct kvm_irq_level a15_vtimer_irq = { static const struct kvm_irq_level cortexa_vtimer_irq = {
{ .irq = 27 }, { .irq = 27 },
.level = 1, .level = 1,
}; };
@ -62,12 +60,11 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
const struct kvm_irq_level *cpu_vtimer_irq; const struct kvm_irq_level *cpu_vtimer_irq;
switch (vcpu->arch.target) { switch (vcpu->arch.target) {
case KVM_ARM_TARGET_CORTEX_A7:
case KVM_ARM_TARGET_CORTEX_A15: case KVM_ARM_TARGET_CORTEX_A15:
if (vcpu->vcpu_id > a15_max_cpu_idx) reset_regs = &cortexa_regs_reset;
return -EINVAL;
reset_regs = &a15_regs_reset;
vcpu->arch.midr = read_cpuid_id(); vcpu->arch.midr = read_cpuid_id();
cpu_vtimer_irq = &a15_vtimer_irq; cpu_vtimer_irq = &cortexa_vtimer_irq;
break; break;
default: default:
return -ENODEV; return -ENODEV;

View file

@ -63,6 +63,7 @@
* TAC: Trap ACTLR * TAC: Trap ACTLR
* TSC: Trap SMC * TSC: Trap SMC
* TSW: Trap cache operations by set/way * TSW: Trap cache operations by set/way
* TWE: Trap WFE
* TWI: Trap WFI * TWI: Trap WFI
* TIDCP: Trap L2CTLR/L2ECTLR * TIDCP: Trap L2CTLR/L2ECTLR
* BSU_IS: Upgrade barriers to the inner shareable domain * BSU_IS: Upgrade barriers to the inner shareable domain
@ -72,8 +73,9 @@
* FMO: Override CPSR.F and enable signaling with VF * FMO: Override CPSR.F and enable signaling with VF
* SWIO: Turn set/way invalidates into set/way clean+invalidate * SWIO: Turn set/way invalidates into set/way clean+invalidate
*/ */
#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \ #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \ HCR_BSU_IS | HCR_FB | HCR_TAC | \
HCR_AMO | HCR_IMO | HCR_FMO | \
HCR_SWIO | HCR_TIDCP | HCR_RW) HCR_SWIO | HCR_TIDCP | HCR_RW)
#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF) #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
@ -242,4 +244,6 @@
#define ESR_EL2_EC_xABT_xFSR_EXTABT 0x10 #define ESR_EL2_EC_xABT_xFSR_EXTABT 0x10
#define ESR_EL2_EC_WFI_ISS_WFE (1 << 0)
#endif /* __ARM64_KVM_ARM_H__ */ #endif /* __ARM64_KVM_ARM_H__ */

View file

@ -177,4 +177,65 @@ static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC_TYPE; return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC_TYPE;
} }
static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu)
{
return vcpu_sys_reg(vcpu, MPIDR_EL1);
}
static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu)
{
if (vcpu_mode_is_32bit(vcpu))
*vcpu_cpsr(vcpu) |= COMPAT_PSR_E_BIT;
else
vcpu_sys_reg(vcpu, SCTLR_EL1) |= (1 << 25);
}
static inline bool kvm_vcpu_is_be(struct kvm_vcpu *vcpu)
{
if (vcpu_mode_is_32bit(vcpu))
return !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_E_BIT);
return !!(vcpu_sys_reg(vcpu, SCTLR_EL1) & (1 << 25));
}
static inline unsigned long vcpu_data_guest_to_host(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
{
if (kvm_vcpu_is_be(vcpu)) {
switch (len) {
case 1:
return data & 0xff;
case 2:
return be16_to_cpu(data & 0xffff);
case 4:
return be32_to_cpu(data & 0xffffffff);
default:
return be64_to_cpu(data);
}
}
return data; /* Leave LE untouched */
}
static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
unsigned long data,
unsigned int len)
{
if (kvm_vcpu_is_be(vcpu)) {
switch (len) {
case 1:
return data & 0xff;
case 2:
return cpu_to_be16(data & 0xffff);
case 4:
return cpu_to_be32(data & 0xffffffff);
default:
return cpu_to_be64(data);
}
}
return data; /* Leave LE untouched */
}
#endif /* __ARM64_KVM_EMULATE_H__ */ #endif /* __ARM64_KVM_EMULATE_H__ */

View file

@ -36,11 +36,6 @@
#define KVM_VCPU_MAX_FEATURES 2 #define KVM_VCPU_MAX_FEATURES 2
/* We don't currently support large pages. */
#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
struct kvm_vcpu; struct kvm_vcpu;
int kvm_target_cpu(void); int kvm_target_cpu(void);
int kvm_reset_vcpu(struct kvm_vcpu *vcpu); int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
@ -151,6 +146,7 @@ struct kvm_vcpu_stat {
struct kvm_vcpu_init; struct kvm_vcpu_init;
int kvm_vcpu_set_target(struct kvm_vcpu *vcpu, int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_init *init); const struct kvm_vcpu_init *init);
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu); unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
struct kvm_one_reg; struct kvm_one_reg;

View file

@ -91,6 +91,7 @@ int kvm_mmu_init(void);
void kvm_clear_hyp_idmap(void); void kvm_clear_hyp_idmap(void);
#define kvm_set_pte(ptep, pte) set_pte(ptep, pte) #define kvm_set_pte(ptep, pte) set_pte(ptep, pte)
#define kvm_set_pmd(pmdp, pmd) set_pmd(pmdp, pmd)
static inline bool kvm_is_write_fault(unsigned long esr) static inline bool kvm_is_write_fault(unsigned long esr)
{ {
@ -116,13 +117,18 @@ static inline void kvm_set_s2pte_writable(pte_t *pte)
pte_val(*pte) |= PTE_S2_RDWR; pte_val(*pte) |= PTE_S2_RDWR;
} }
static inline void kvm_set_s2pmd_writable(pmd_t *pmd)
{
pmd_val(*pmd) |= PMD_S2_RDWR;
}
struct kvm; struct kvm;
static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn) static inline void coherent_icache_guest_page(struct kvm *kvm, hva_t hva,
unsigned long size)
{ {
if (!icache_is_aliasing()) { /* PIPT */ if (!icache_is_aliasing()) { /* PIPT */
unsigned long hva = gfn_to_hva(kvm, gfn); flush_icache_range(hva, hva + size);
flush_icache_range(hva, hva + PAGE_SIZE);
} else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */ } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
/* any kind of VIPT cache */ /* any kind of VIPT cache */
__flush_icache_all(); __flush_icache_all();

View file

@ -85,6 +85,8 @@
#define PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[2:1] */ #define PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[2:1] */
#define PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */ #define PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
/* /*
* Memory Attribute override for Stage-2 (MemAttr[3:0]) * Memory Attribute override for Stage-2 (MemAttr[3:0])
*/ */

View file

@ -21,6 +21,7 @@ config KVM
select MMU_NOTIFIER select MMU_NOTIFIER
select PREEMPT_NOTIFIERS select PREEMPT_NOTIFIERS
select ANON_INODES select ANON_INODES
select HAVE_KVM_CPU_RELAX_INTERCEPT
select KVM_MMIO select KVM_MMIO
select KVM_ARM_HOST select KVM_ARM_HOST
select KVM_ARM_VGIC select KVM_ARM_VGIC

View file

@ -248,6 +248,26 @@ int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
return kvm_reset_vcpu(vcpu); return kvm_reset_vcpu(vcpu);
} }
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init)
{
int target = kvm_target_cpu();
if (target < 0)
return -ENODEV;
memset(init, 0, sizeof(*init));
/*
* For now, we don't return any features.
* In future, we might use features to return target
* specific features available for the preferred
* target type.
*/
init->target = (__u32)target;
return 0;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{ {
return -EINVAL; return -EINVAL;

View file

@ -47,21 +47,29 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
} }
/** /**
* kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest * kvm_handle_wfx - handle a wait-for-interrupts or wait-for-event
* instruction executed by a guest
*
* @vcpu: the vcpu pointer * @vcpu: the vcpu pointer
* *
* Simply call kvm_vcpu_block(), which will halt execution of * WFE: Yield the CPU and come back to this vcpu when the scheduler
* decides to.
* WFI: Simply call kvm_vcpu_block(), which will halt execution of
* world-switches and schedule other host processes until there is an * world-switches and schedule other host processes until there is an
* incoming IRQ or FIQ to the VM. * incoming IRQ or FIQ to the VM.
*/ */
static int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run) static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
kvm_vcpu_block(vcpu); if (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EC_WFI_ISS_WFE)
kvm_vcpu_on_spin(vcpu);
else
kvm_vcpu_block(vcpu);
return 1; return 1;
} }
static exit_handle_fn arm_exit_handlers[] = { static exit_handle_fn arm_exit_handlers[] = {
[ESR_EL2_EC_WFI] = kvm_handle_wfi, [ESR_EL2_EC_WFI] = kvm_handle_wfx,
[ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32, [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32,
[ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64, [ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64,
[ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_access, [ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_access,

View file

@ -234,10 +234,6 @@ struct kvm_vm_data {
#define KVM_REQ_PTC_G 32 #define KVM_REQ_PTC_G 32
#define KVM_REQ_RESUME 33 #define KVM_REQ_RESUME 33
#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) 1
struct kvm; struct kvm;
struct kvm_vcpu; struct kvm_vcpu;
@ -480,7 +476,7 @@ struct kvm_arch {
struct list_head assigned_dev_head; struct list_head assigned_dev_head;
struct iommu_domain *iommu_domain; struct iommu_domain *iommu_domain;
int iommu_flags; bool iommu_noncoherent;
unsigned long irq_sources_bitmap; unsigned long irq_sources_bitmap;
unsigned long irq_states[KVM_IOAPIC_NUM_PINS]; unsigned long irq_states[KVM_IOAPIC_NUM_PINS];

View file

@ -1550,12 +1550,13 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
return VM_FAULT_SIGBUS; return VM_FAULT_SIGBUS;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free, void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
} }
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages)
{ {
return 0; return 0;
} }

View file

@ -27,13 +27,6 @@
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
/* Don't support huge pages */
#define KVM_HPAGE_GFN_SHIFT(x) 0
/* We don't currently support large pages. */
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) 1
/* Special address that contains the comm page, used for reducing # of traps */ /* Special address that contains the comm page, used for reducing # of traps */

View file

@ -198,12 +198,13 @@ kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free, void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
} }
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages)
{ {
return 0; return 0;
} }

View file

@ -77,4 +77,8 @@ static inline unsigned int get_d(u32 inst)
return inst & 0xffff; return inst & 0xffff;
} }
static inline unsigned int get_oc(u32 inst)
{
return (inst >> 11) & 0x7fff;
}
#endif /* __ASM_PPC_DISASSEMBLE_H__ */ #endif /* __ASM_PPC_DISASSEMBLE_H__ */

View file

@ -198,12 +198,27 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
cmpwi r10,0; \ cmpwi r10,0; \
bne do_kvm_##n bne do_kvm_##n
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
/*
* If hv is possible, interrupts come into to the hv version
* of the kvmppc_interrupt code, which then jumps to the PR handler,
* kvmppc_interrupt_pr, if the guest is a PR guest.
*/
#define kvmppc_interrupt kvmppc_interrupt_hv
#else
#define kvmppc_interrupt kvmppc_interrupt_pr
#endif
#define __KVM_HANDLER(area, h, n) \ #define __KVM_HANDLER(area, h, n) \
do_kvm_##n: \ do_kvm_##n: \
BEGIN_FTR_SECTION_NESTED(947) \ BEGIN_FTR_SECTION_NESTED(947) \
ld r10,area+EX_CFAR(r13); \ ld r10,area+EX_CFAR(r13); \
std r10,HSTATE_CFAR(r13); \ std r10,HSTATE_CFAR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_CFAR,CPU_FTR_CFAR,947); \ END_FTR_SECTION_NESTED(CPU_FTR_CFAR,CPU_FTR_CFAR,947); \
BEGIN_FTR_SECTION_NESTED(948) \
ld r10,area+EX_PPR(r13); \
std r10,HSTATE_PPR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
ld r10,area+EX_R10(r13); \ ld r10,area+EX_R10(r13); \
stw r9,HSTATE_SCRATCH1(r13); \ stw r9,HSTATE_SCRATCH1(r13); \
ld r9,area+EX_R9(r13); \ ld r9,area+EX_R9(r13); \
@ -217,6 +232,10 @@ do_kvm_##n: \
ld r10,area+EX_R10(r13); \ ld r10,area+EX_R10(r13); \
beq 89f; \ beq 89f; \
stw r9,HSTATE_SCRATCH1(r13); \ stw r9,HSTATE_SCRATCH1(r13); \
BEGIN_FTR_SECTION_NESTED(948) \
ld r9,area+EX_PPR(r13); \
std r9,HSTATE_PPR(r13); \
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
ld r9,area+EX_R9(r13); \ ld r9,area+EX_R9(r13); \
std r12,HSTATE_SCRATCH0(r13); \ std r12,HSTATE_SCRATCH0(r13); \
li r12,n; \ li r12,n; \
@ -236,7 +255,7 @@ do_kvm_##n: \
#define KVM_HANDLER_SKIP(area, h, n) #define KVM_HANDLER_SKIP(area, h, n)
#endif #endif
#ifdef CONFIG_KVM_BOOK3S_PR #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
#define KVMTEST_PR(n) __KVMTEST(n) #define KVMTEST_PR(n) __KVMTEST(n)
#define KVM_HANDLER_PR(area, h, n) __KVM_HANDLER(area, h, n) #define KVM_HANDLER_PR(area, h, n) __KVM_HANDLER(area, h, n)
#define KVM_HANDLER_PR_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n) #define KVM_HANDLER_PR_SKIP(area, h, n) __KVM_HANDLER_SKIP(area, h, n)

View file

@ -123,6 +123,8 @@
#define BOOK3S_HFLAG_SLB 0x2 #define BOOK3S_HFLAG_SLB 0x2
#define BOOK3S_HFLAG_PAIRED_SINGLE 0x4 #define BOOK3S_HFLAG_PAIRED_SINGLE 0x4
#define BOOK3S_HFLAG_NATIVE_PS 0x8 #define BOOK3S_HFLAG_NATIVE_PS 0x8
#define BOOK3S_HFLAG_MULTI_PGSIZE 0x10
#define BOOK3S_HFLAG_NEW_TLBIE 0x20
#define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */
#define RESUME_FLAG_HOST (1<<1) /* Resume host? */ #define RESUME_FLAG_HOST (1<<1) /* Resume host? */
@ -136,6 +138,8 @@
#define KVM_GUEST_MODE_NONE 0 #define KVM_GUEST_MODE_NONE 0
#define KVM_GUEST_MODE_GUEST 1 #define KVM_GUEST_MODE_GUEST 1
#define KVM_GUEST_MODE_SKIP 2 #define KVM_GUEST_MODE_SKIP 2
#define KVM_GUEST_MODE_GUEST_HV 3
#define KVM_GUEST_MODE_HOST_HV 4
#define KVM_INST_FETCH_FAILED -1 #define KVM_INST_FETCH_FAILED -1

View file

@ -58,16 +58,18 @@ struct hpte_cache {
struct hlist_node list_pte_long; struct hlist_node list_pte_long;
struct hlist_node list_vpte; struct hlist_node list_vpte;
struct hlist_node list_vpte_long; struct hlist_node list_vpte_long;
#ifdef CONFIG_PPC_BOOK3S_64
struct hlist_node list_vpte_64k;
#endif
struct rcu_head rcu_head; struct rcu_head rcu_head;
u64 host_vpn; u64 host_vpn;
u64 pfn; u64 pfn;
ulong slot; ulong slot;
struct kvmppc_pte pte; struct kvmppc_pte pte;
int pagesize;
}; };
struct kvmppc_vcpu_book3s { struct kvmppc_vcpu_book3s {
struct kvm_vcpu vcpu;
struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
struct kvmppc_sid_map sid_map[SID_MAP_NUM]; struct kvmppc_sid_map sid_map[SID_MAP_NUM];
struct { struct {
u64 esid; u64 esid;
@ -99,6 +101,9 @@ struct kvmppc_vcpu_book3s {
struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG]; struct hlist_head hpte_hash_pte_long[HPTEG_HASH_NUM_PTE_LONG];
struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE]; struct hlist_head hpte_hash_vpte[HPTEG_HASH_NUM_VPTE];
struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG]; struct hlist_head hpte_hash_vpte_long[HPTEG_HASH_NUM_VPTE_LONG];
#ifdef CONFIG_PPC_BOOK3S_64
struct hlist_head hpte_hash_vpte_64k[HPTEG_HASH_NUM_VPTE_64K];
#endif
int hpte_cache_count; int hpte_cache_count;
spinlock_t mmu_lock; spinlock_t mmu_lock;
}; };
@ -107,8 +112,9 @@ struct kvmppc_vcpu_book3s {
#define CONTEXT_GUEST 1 #define CONTEXT_GUEST 1
#define CONTEXT_GUEST_END 2 #define CONTEXT_GUEST_END 2
#define VSID_REAL 0x0fffffffffc00000ULL #define VSID_REAL 0x07ffffffffc00000ULL
#define VSID_BAT 0x0fffffffffb00000ULL #define VSID_BAT 0x07ffffffffb00000ULL
#define VSID_64K 0x0800000000000000ULL
#define VSID_1T 0x1000000000000000ULL #define VSID_1T 0x1000000000000000ULL
#define VSID_REAL_DR 0x2000000000000000ULL #define VSID_REAL_DR 0x2000000000000000ULL
#define VSID_REAL_IR 0x4000000000000000ULL #define VSID_REAL_IR 0x4000000000000000ULL
@ -118,11 +124,12 @@ extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong ea, ulong ea_mask)
extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask); extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask);
extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end); extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end);
extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr); extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr);
extern void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr);
extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu);
extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte); extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte,
bool iswrite);
extern void kvmppc_mmu_unmap_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr); extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
extern void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong eaddr, ulong seg_size); extern void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong eaddr, ulong seg_size);
extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
@ -134,6 +141,7 @@ extern long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr,
extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte); extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu); extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_hpte_cache_free(struct hpte_cache *pte);
extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu);
extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu); extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte); extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
@ -151,7 +159,8 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
bool upper, u32 val); bool upper, u32 val);
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu); extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, bool writing,
bool *writable);
extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev, extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
unsigned long *rmap, long pte_index, int realmode); unsigned long *rmap, long pte_index, int realmode);
extern void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep, extern void kvmppc_invalidate_hpte(struct kvm *kvm, unsigned long *hptep,
@ -172,6 +181,8 @@ extern long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
unsigned long *hpret); unsigned long *hpret);
extern long kvmppc_hv_get_dirty_log(struct kvm *kvm, extern long kvmppc_hv_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot, unsigned long *map); struct kvm_memory_slot *memslot, unsigned long *map);
extern void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr,
unsigned long mask);
extern void kvmppc_entry_trampoline(void); extern void kvmppc_entry_trampoline(void);
extern void kvmppc_hv_entry_trampoline(void); extern void kvmppc_hv_entry_trampoline(void);
@ -184,11 +195,9 @@ extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd);
static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu)
{ {
return container_of(vcpu, struct kvmppc_vcpu_book3s, vcpu); return vcpu->arch.book3s;
} }
extern void kvm_return_point(void);
/* Also add subarch specific defines */ /* Also add subarch specific defines */
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
@ -198,203 +207,6 @@ extern void kvm_return_point(void);
#include <asm/kvm_book3s_64.h> #include <asm/kvm_book3s_64.h>
#endif #endif
#ifdef CONFIG_KVM_BOOK3S_PR
static inline unsigned long kvmppc_interrupt_offset(struct kvm_vcpu *vcpu)
{
return to_book3s(vcpu)->hior;
}
static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
unsigned long pending_now, unsigned long old_pending)
{
if (pending_now)
vcpu->arch.shared->int_pending = 1;
else if (old_pending)
vcpu->arch.shared->int_pending = 0;
}
static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
{
if ( num < 14 ) {
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->gpr[num] = val;
svcpu_put(svcpu);
to_book3s(vcpu)->shadow_vcpu->gpr[num] = val;
} else
vcpu->arch.gpr[num] = val;
}
static inline ulong kvmppc_get_gpr(struct kvm_vcpu *vcpu, int num)
{
if ( num < 14 ) {
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
ulong r = svcpu->gpr[num];
svcpu_put(svcpu);
return r;
} else
return vcpu->arch.gpr[num];
}
static inline void kvmppc_set_cr(struct kvm_vcpu *vcpu, u32 val)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->cr = val;
svcpu_put(svcpu);
to_book3s(vcpu)->shadow_vcpu->cr = val;
}
static inline u32 kvmppc_get_cr(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
u32 r;
r = svcpu->cr;
svcpu_put(svcpu);
return r;
}
static inline void kvmppc_set_xer(struct kvm_vcpu *vcpu, u32 val)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->xer = val;
to_book3s(vcpu)->shadow_vcpu->xer = val;
svcpu_put(svcpu);
}
static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
u32 r;
r = svcpu->xer;
svcpu_put(svcpu);
return r;
}
static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->ctr = val;
svcpu_put(svcpu);
}
static inline ulong kvmppc_get_ctr(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
ulong r;
r = svcpu->ctr;
svcpu_put(svcpu);
return r;
}
static inline void kvmppc_set_lr(struct kvm_vcpu *vcpu, ulong val)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->lr = val;
svcpu_put(svcpu);
}
static inline ulong kvmppc_get_lr(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
ulong r;
r = svcpu->lr;
svcpu_put(svcpu);
return r;
}
static inline void kvmppc_set_pc(struct kvm_vcpu *vcpu, ulong val)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
svcpu->pc = val;
svcpu_put(svcpu);
}
static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
ulong r;
r = svcpu->pc;
svcpu_put(svcpu);
return r;
}
static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
{
ulong pc = kvmppc_get_pc(vcpu);
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
u32 r;
/* Load the instruction manually if it failed to do so in the
* exit path */
if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);
r = svcpu->last_inst;
svcpu_put(svcpu);
return r;
}
/*
* Like kvmppc_get_last_inst(), but for fetching a sc instruction.
* Because the sc instruction sets SRR0 to point to the following
* instruction, we have to fetch from pc - 4.
*/
static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
{
ulong pc = kvmppc_get_pc(vcpu) - 4;
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
u32 r;
/* Load the instruction manually if it failed to do so in the
* exit path */
if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);
r = svcpu->last_inst;
svcpu_put(svcpu);
return r;
}
static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
ulong r;
r = svcpu->fault_dar;
svcpu_put(svcpu);
return r;
}
static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
{
ulong crit_raw = vcpu->arch.shared->critical;
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
bool crit;
/* Truncate crit indicators in 32 bit mode */
if (!(vcpu->arch.shared->msr & MSR_SF)) {
crit_raw &= 0xffffffff;
crit_r1 &= 0xffffffff;
}
/* Critical section when crit == r1 */
crit = (crit_raw == crit_r1);
/* ... and we're in supervisor mode */
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
return crit;
}
#else /* CONFIG_KVM_BOOK3S_PR */
static inline unsigned long kvmppc_interrupt_offset(struct kvm_vcpu *vcpu)
{
return 0;
}
static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
unsigned long pending_now, unsigned long old_pending)
{
}
static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
{ {
vcpu->arch.gpr[num] = val; vcpu->arch.gpr[num] = val;
@ -489,12 +301,6 @@ static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
return vcpu->arch.fault_dar; return vcpu->arch.fault_dar;
} }
static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
{
return false;
}
#endif
/* Magic register values loaded into r3 and r4 before the 'sc' assembly /* Magic register values loaded into r3 and r4 before the 'sc' assembly
* instruction for the OSI hypercalls */ * instruction for the OSI hypercalls */
#define OSI_SC_MAGIC_R3 0x113724FA #define OSI_SC_MAGIC_R3 0x113724FA

View file

@ -22,7 +22,7 @@
static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu) static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
{ {
return to_book3s(vcpu)->shadow_vcpu; return vcpu->arch.shadow_vcpu;
} }
static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu) static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)

View file

@ -20,7 +20,7 @@
#ifndef __ASM_KVM_BOOK3S_64_H__ #ifndef __ASM_KVM_BOOK3S_64_H__
#define __ASM_KVM_BOOK3S_64_H__ #define __ASM_KVM_BOOK3S_64_H__
#ifdef CONFIG_KVM_BOOK3S_PR #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu) static inline struct kvmppc_book3s_shadow_vcpu *svcpu_get(struct kvm_vcpu *vcpu)
{ {
preempt_disable(); preempt_disable();
@ -35,7 +35,7 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
#define SPAPR_TCE_SHIFT 12 #define SPAPR_TCE_SHIFT 12
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
#define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */ #define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */
extern unsigned long kvm_rma_pages; extern unsigned long kvm_rma_pages;
#endif #endif
@ -278,7 +278,7 @@ static inline int is_vrma_hpte(unsigned long hpte_v)
(HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16))); (HPTE_V_1TB_SEG | (VRMA_VSID << (40 - 16)));
} }
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
/* /*
* Note modification of an HPTE; set the HPTE modified bit * Note modification of an HPTE; set the HPTE modified bit
* if anyone is interested. * if anyone is interested.
@ -289,6 +289,6 @@ static inline void note_hpte_modification(struct kvm *kvm,
if (atomic_read(&kvm->arch.hpte_mod_interest)) if (atomic_read(&kvm->arch.hpte_mod_interest))
rev->guest_rpte |= HPTE_GR_MODIFIED; rev->guest_rpte |= HPTE_GR_MODIFIED;
} }
#endif /* CONFIG_KVM_BOOK3S_64_HV */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#endif /* __ASM_KVM_BOOK3S_64_H__ */ #endif /* __ASM_KVM_BOOK3S_64_H__ */

View file

@ -83,7 +83,7 @@ struct kvmppc_host_state {
u8 restore_hid5; u8 restore_hid5;
u8 napping; u8 napping;
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
u8 hwthread_req; u8 hwthread_req;
u8 hwthread_state; u8 hwthread_state;
u8 host_ipi; u8 host_ipi;
@ -101,6 +101,7 @@ struct kvmppc_host_state {
#endif #endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
u64 cfar; u64 cfar;
u64 ppr;
#endif #endif
}; };
@ -108,14 +109,14 @@ struct kvmppc_book3s_shadow_vcpu {
ulong gpr[14]; ulong gpr[14];
u32 cr; u32 cr;
u32 xer; u32 xer;
u32 fault_dsisr;
u32 last_inst;
ulong ctr; ulong ctr;
ulong lr; ulong lr;
ulong pc; ulong pc;
ulong shadow_srr1; ulong shadow_srr1;
ulong fault_dar; ulong fault_dar;
u32 fault_dsisr;
u32 last_inst;
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
u32 sr[16]; /* Guest SRs */ u32 sr[16]; /* Guest SRs */

View file

@ -26,7 +26,12 @@
/* LPIDs we support with this build -- runtime limit may be lower */ /* LPIDs we support with this build -- runtime limit may be lower */
#define KVMPPC_NR_LPIDS 64 #define KVMPPC_NR_LPIDS 64
#define KVMPPC_INST_EHPRIV 0x7c00021c #define KVMPPC_INST_EHPRIV 0x7c00021c
#define EHPRIV_OC_SHIFT 11
/* "ehpriv 1" : ehpriv with OC = 1 is used for debug emulation */
#define EHPRIV_OC_DEBUG 1
#define KVMPPC_INST_EHPRIV_DEBUG (KVMPPC_INST_EHPRIV | \
(EHPRIV_OC_DEBUG << EHPRIV_OC_SHIFT))
static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val) static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
{ {

View file

@ -63,20 +63,17 @@ extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
#endif #endif
/* We don't currently support large pages. */
#define KVM_HPAGE_GFN_SHIFT(x) 0
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
#define HPTEG_CACHE_NUM (1 << 15) #define HPTEG_CACHE_NUM (1 << 15)
#define HPTEG_HASH_BITS_PTE 13 #define HPTEG_HASH_BITS_PTE 13
#define HPTEG_HASH_BITS_PTE_LONG 12 #define HPTEG_HASH_BITS_PTE_LONG 12
#define HPTEG_HASH_BITS_VPTE 13 #define HPTEG_HASH_BITS_VPTE 13
#define HPTEG_HASH_BITS_VPTE_LONG 5 #define HPTEG_HASH_BITS_VPTE_LONG 5
#define HPTEG_HASH_BITS_VPTE_64K 11
#define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE) #define HPTEG_HASH_NUM_PTE (1 << HPTEG_HASH_BITS_PTE)
#define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG) #define HPTEG_HASH_NUM_PTE_LONG (1 << HPTEG_HASH_BITS_PTE_LONG)
#define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE) #define HPTEG_HASH_NUM_VPTE (1 << HPTEG_HASH_BITS_VPTE)
#define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG) #define HPTEG_HASH_NUM_VPTE_LONG (1 << HPTEG_HASH_BITS_VPTE_LONG)
#define HPTEG_HASH_NUM_VPTE_64K (1 << HPTEG_HASH_BITS_VPTE_64K)
/* Physical Address Mask - allowed range of real mode RAM access */ /* Physical Address Mask - allowed range of real mode RAM access */
#define KVM_PAM 0x0fffffffffffffffULL #define KVM_PAM 0x0fffffffffffffffULL
@ -89,6 +86,9 @@ struct lppaca;
struct slb_shadow; struct slb_shadow;
struct dtl_entry; struct dtl_entry;
struct kvmppc_vcpu_book3s;
struct kvmppc_book3s_shadow_vcpu;
struct kvm_vm_stat { struct kvm_vm_stat {
u32 remote_tlb_flush; u32 remote_tlb_flush;
}; };
@ -224,15 +224,15 @@ struct revmap_entry {
#define KVMPPC_GOT_PAGE 0x80 #define KVMPPC_GOT_PAGE 0x80
struct kvm_arch_memory_slot { struct kvm_arch_memory_slot {
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
unsigned long *rmap; unsigned long *rmap;
unsigned long *slot_phys; unsigned long *slot_phys;
#endif /* CONFIG_KVM_BOOK3S_64_HV */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
}; };
struct kvm_arch { struct kvm_arch {
unsigned int lpid; unsigned int lpid;
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
unsigned long hpt_virt; unsigned long hpt_virt;
struct revmap_entry *revmap; struct revmap_entry *revmap;
unsigned int host_lpid; unsigned int host_lpid;
@ -256,7 +256,10 @@ struct kvm_arch {
cpumask_t need_tlb_flush; cpumask_t need_tlb_flush;
struct kvmppc_vcore *vcores[KVM_MAX_VCORES]; struct kvmppc_vcore *vcores[KVM_MAX_VCORES];
int hpt_cma_alloc; int hpt_cma_alloc;
#endif /* CONFIG_KVM_BOOK3S_64_HV */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
struct mutex hpt_mutex;
#endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
struct list_head spapr_tce_tables; struct list_head spapr_tce_tables;
struct list_head rtas_tokens; struct list_head rtas_tokens;
@ -267,6 +270,7 @@ struct kvm_arch {
#ifdef CONFIG_KVM_XICS #ifdef CONFIG_KVM_XICS
struct kvmppc_xics *xics; struct kvmppc_xics *xics;
#endif #endif
struct kvmppc_ops *kvm_ops;
}; };
/* /*
@ -294,6 +298,10 @@ struct kvmppc_vcore {
u64 stolen_tb; u64 stolen_tb;
u64 preempt_tb; u64 preempt_tb;
struct kvm_vcpu *runner; struct kvm_vcpu *runner;
u64 tb_offset; /* guest timebase - host timebase */
ulong lpcr;
u32 arch_compat;
ulong pcr;
}; };
#define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff) #define VCORE_ENTRY_COUNT(vc) ((vc)->entry_exit_count & 0xff)
@ -328,6 +336,7 @@ struct kvmppc_pte {
bool may_read : 1; bool may_read : 1;
bool may_write : 1; bool may_write : 1;
bool may_execute : 1; bool may_execute : 1;
u8 page_size; /* MMU_PAGE_xxx */
}; };
struct kvmppc_mmu { struct kvmppc_mmu {
@ -340,7 +349,8 @@ struct kvmppc_mmu {
/* book3s */ /* book3s */
void (*mtsrin)(struct kvm_vcpu *vcpu, u32 srnum, ulong value); void (*mtsrin)(struct kvm_vcpu *vcpu, u32 srnum, ulong value);
u32 (*mfsrin)(struct kvm_vcpu *vcpu, u32 srnum); u32 (*mfsrin)(struct kvm_vcpu *vcpu, u32 srnum);
int (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data); int (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data, bool iswrite);
void (*reset_msr)(struct kvm_vcpu *vcpu); void (*reset_msr)(struct kvm_vcpu *vcpu);
void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large); void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large);
int (*esid_to_vsid)(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid); int (*esid_to_vsid)(struct kvm_vcpu *vcpu, ulong esid, u64 *vsid);
@ -360,6 +370,7 @@ struct kvmppc_slb {
bool large : 1; /* PTEs are 16MB */ bool large : 1; /* PTEs are 16MB */
bool tb : 1; /* 1TB segment */ bool tb : 1; /* 1TB segment */
bool class : 1; bool class : 1;
u8 base_page_size; /* MMU_PAGE_xxx */
}; };
# ifdef CONFIG_PPC_FSL_BOOK3E # ifdef CONFIG_PPC_FSL_BOOK3E
@ -377,17 +388,6 @@ struct kvmppc_slb {
#define KVMPPC_EPR_USER 1 /* exit to userspace to fill EPR */ #define KVMPPC_EPR_USER 1 /* exit to userspace to fill EPR */
#define KVMPPC_EPR_KERNEL 2 /* in-kernel irqchip */ #define KVMPPC_EPR_KERNEL 2 /* in-kernel irqchip */
struct kvmppc_booke_debug_reg {
u32 dbcr0;
u32 dbcr1;
u32 dbcr2;
#ifdef CONFIG_KVM_E500MC
u32 dbcr4;
#endif
u64 iac[KVMPPC_BOOKE_MAX_IAC];
u64 dac[KVMPPC_BOOKE_MAX_DAC];
};
#define KVMPPC_IRQ_DEFAULT 0 #define KVMPPC_IRQ_DEFAULT 0
#define KVMPPC_IRQ_MPIC 1 #define KVMPPC_IRQ_MPIC 1
#define KVMPPC_IRQ_XICS 2 #define KVMPPC_IRQ_XICS 2
@ -402,6 +402,10 @@ struct kvm_vcpu_arch {
int slb_max; /* 1 + index of last valid entry in slb[] */ int slb_max; /* 1 + index of last valid entry in slb[] */
int slb_nr; /* total number of entries in SLB */ int slb_nr; /* total number of entries in SLB */
struct kvmppc_mmu mmu; struct kvmppc_mmu mmu;
struct kvmppc_vcpu_book3s *book3s;
#endif
#ifdef CONFIG_PPC_BOOK3S_32
struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
#endif #endif
ulong gpr[32]; ulong gpr[32];
@ -463,6 +467,8 @@ struct kvm_vcpu_arch {
u32 ctrl; u32 ctrl;
ulong dabr; ulong dabr;
ulong cfar; ulong cfar;
ulong ppr;
ulong shadow_srr1;
#endif #endif
u32 vrsave; /* also USPRG0 */ u32 vrsave; /* also USPRG0 */
u32 mmucr; u32 mmucr;
@ -498,6 +504,8 @@ struct kvm_vcpu_arch {
u64 mmcr[3]; u64 mmcr[3];
u32 pmc[8]; u32 pmc[8];
u64 siar;
u64 sdar;
#ifdef CONFIG_KVM_EXIT_TIMING #ifdef CONFIG_KVM_EXIT_TIMING
struct mutex exit_timing_lock; struct mutex exit_timing_lock;
@ -531,7 +539,10 @@ struct kvm_vcpu_arch {
u32 eptcfg; u32 eptcfg;
u32 epr; u32 epr;
u32 crit_save; u32 crit_save;
struct kvmppc_booke_debug_reg dbg_reg; /* guest debug registers*/
struct debug_reg dbg_reg;
/* hardware visible debug registers when in guest state */
struct debug_reg shadow_dbg_reg;
#endif #endif
gpa_t paddr_accessed; gpa_t paddr_accessed;
gva_t vaddr_accessed; gva_t vaddr_accessed;
@ -582,7 +593,7 @@ struct kvm_vcpu_arch {
struct kvmppc_icp *icp; /* XICS presentation controller */ struct kvmppc_icp *icp; /* XICS presentation controller */
#endif #endif
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
struct kvm_vcpu_arch_shared shregs; struct kvm_vcpu_arch_shared shregs;
unsigned long pgfault_addr; unsigned long pgfault_addr;

View file

@ -106,13 +106,6 @@ extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq); struct kvm_interrupt *irq);
extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu); extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu);
extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu); extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu);
extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int op, int *advance);
extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn,
ulong val);
extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn,
ulong *val);
extern int kvmppc_core_check_requests(struct kvm_vcpu *vcpu); extern int kvmppc_core_check_requests(struct kvm_vcpu *vcpu);
extern int kvmppc_booke_init(void); extern int kvmppc_booke_init(void);
@ -135,17 +128,17 @@ extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
struct kvm_create_spapr_tce *args); struct kvm_create_spapr_tce *args);
extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, extern long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
unsigned long ioba, unsigned long tce); unsigned long ioba, unsigned long tce);
extern long kvm_vm_ioctl_allocate_rma(struct kvm *kvm,
struct kvm_allocate_rma *rma);
extern struct kvm_rma_info *kvm_alloc_rma(void); extern struct kvm_rma_info *kvm_alloc_rma(void);
extern void kvm_release_rma(struct kvm_rma_info *ri); extern void kvm_release_rma(struct kvm_rma_info *ri);
extern struct page *kvm_alloc_hpt(unsigned long nr_pages); extern struct page *kvm_alloc_hpt(unsigned long nr_pages);
extern void kvm_release_hpt(struct page *page, unsigned long nr_pages); extern void kvm_release_hpt(struct page *page, unsigned long nr_pages);
extern int kvmppc_core_init_vm(struct kvm *kvm); extern int kvmppc_core_init_vm(struct kvm *kvm);
extern void kvmppc_core_destroy_vm(struct kvm *kvm); extern void kvmppc_core_destroy_vm(struct kvm *kvm);
extern void kvmppc_core_free_memslot(struct kvm_memory_slot *free, extern void kvmppc_core_free_memslot(struct kvm *kvm,
struct kvm_memory_slot *free,
struct kvm_memory_slot *dont); struct kvm_memory_slot *dont);
extern int kvmppc_core_create_memslot(struct kvm_memory_slot *slot, extern int kvmppc_core_create_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot,
unsigned long npages); unsigned long npages);
extern int kvmppc_core_prepare_memory_region(struct kvm *kvm, extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
@ -177,6 +170,72 @@ extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
extern int kvmppc_xics_int_on(struct kvm *kvm, u32 irq); extern int kvmppc_xics_int_on(struct kvm *kvm, u32 irq);
extern int kvmppc_xics_int_off(struct kvm *kvm, u32 irq); extern int kvmppc_xics_int_off(struct kvm *kvm, u32 irq);
union kvmppc_one_reg {
u32 wval;
u64 dval;
vector128 vval;
u64 vsxval[2];
struct {
u64 addr;
u64 length;
} vpaval;
};
struct kvmppc_ops {
struct module *owner;
int (*get_sregs)(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
int (*set_sregs)(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
int (*get_one_reg)(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val);
int (*set_one_reg)(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val);
void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
void (*set_msr)(struct kvm_vcpu *vcpu, u64 msr);
int (*vcpu_run)(struct kvm_run *run, struct kvm_vcpu *vcpu);
struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned int id);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
int (*check_requests)(struct kvm_vcpu *vcpu);
int (*get_dirty_log)(struct kvm *kvm, struct kvm_dirty_log *log);
void (*flush_memslot)(struct kvm *kvm, struct kvm_memory_slot *memslot);
int (*prepare_memory_region)(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_userspace_memory_region *mem);
void (*commit_memory_region)(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old);
int (*unmap_hva)(struct kvm *kvm, unsigned long hva);
int (*unmap_hva_range)(struct kvm *kvm, unsigned long start,
unsigned long end);
int (*age_hva)(struct kvm *kvm, unsigned long hva);
int (*test_age_hva)(struct kvm *kvm, unsigned long hva);
void (*set_spte_hva)(struct kvm *kvm, unsigned long hva, pte_t pte);
void (*mmu_destroy)(struct kvm_vcpu *vcpu);
void (*free_memslot)(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont);
int (*create_memslot)(struct kvm_memory_slot *slot,
unsigned long npages);
int (*init_vm)(struct kvm *kvm);
void (*destroy_vm)(struct kvm *kvm);
int (*get_smmu_info)(struct kvm *kvm, struct kvm_ppc_smmu_info *info);
int (*emulate_op)(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance);
int (*emulate_mtspr)(struct kvm_vcpu *vcpu, int sprn, ulong spr_val);
int (*emulate_mfspr)(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val);
void (*fast_vcpu_kick)(struct kvm_vcpu *vcpu);
long (*arch_vm_ioctl)(struct file *filp, unsigned int ioctl,
unsigned long arg);
};
extern struct kvmppc_ops *kvmppc_hv_ops;
extern struct kvmppc_ops *kvmppc_pr_ops;
static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
{
return kvm->arch.kvm_ops == kvmppc_hv_ops;
}
/* /*
* Cuts out inst bits with ordering according to spec. * Cuts out inst bits with ordering according to spec.
* That means the leftmost bit is zero. All given bits are included. * That means the leftmost bit is zero. All given bits are included.
@ -210,17 +269,6 @@ static inline u32 kvmppc_set_field(u64 inst, int msb, int lsb, int value)
return r; return r;
} }
union kvmppc_one_reg {
u32 wval;
u64 dval;
vector128 vval;
u64 vsxval[2];
struct {
u64 addr;
u64 length;
} vpaval;
};
#define one_reg_size(id) \ #define one_reg_size(id) \
(1ul << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT)) (1ul << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
@ -245,10 +293,10 @@ union kvmppc_one_reg {
__v; \ __v; \
}) })
void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); int kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); int kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs); int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg); int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
@ -260,7 +308,7 @@ void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid);
struct openpic; struct openpic;
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
extern void kvm_cma_reserve(void) __init; extern void kvm_cma_reserve(void) __init;
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr) static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
{ {
@ -269,10 +317,10 @@ static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
static inline u32 kvmppc_get_xics_latch(void) static inline u32 kvmppc_get_xics_latch(void)
{ {
u32 xirr = get_paca()->kvm_hstate.saved_xirr; u32 xirr;
xirr = get_paca()->kvm_hstate.saved_xirr;
get_paca()->kvm_hstate.saved_xirr = 0; get_paca()->kvm_hstate.saved_xirr = 0;
return xirr; return xirr;
} }
@ -281,7 +329,10 @@ static inline void kvmppc_set_host_ipi(int cpu, u8 host_ipi)
paca[cpu].kvm_hstate.host_ipi = host_ipi; paca[cpu].kvm_hstate.host_ipi = host_ipi;
} }
extern void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu); static inline void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->fast_vcpu_kick(vcpu);
}
#else #else
static inline void __init kvm_cma_reserve(void) static inline void __init kvm_cma_reserve(void)

View file

@ -166,7 +166,7 @@ struct paca_struct {
struct dtl_entry *dtl_curr; /* pointer corresponding to dtl_ridx */ struct dtl_entry *dtl_curr; /* pointer corresponding to dtl_ridx */
#ifdef CONFIG_KVM_BOOK3S_HANDLER #ifdef CONFIG_KVM_BOOK3S_HANDLER
#ifdef CONFIG_KVM_BOOK3S_PR #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
/* We use this to store guest state in */ /* We use this to store guest state in */
struct kvmppc_book3s_shadow_vcpu shadow_vcpu; struct kvmppc_book3s_shadow_vcpu shadow_vcpu;
#endif #endif

View file

@ -208,6 +208,7 @@ struct debug_reg {
struct thread_struct { struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */ unsigned long ksp; /* Kernel stack pointer */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
unsigned long ksp_vsid; unsigned long ksp_vsid;
#endif #endif
@ -221,6 +222,7 @@ struct thread_struct {
void *pgdir; /* root of page-table tree */ void *pgdir; /* root of page-table tree */
unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */ unsigned long ksp_limit; /* if ksp <= ksp_limit stack overflow */
#endif #endif
/* Debug Registers */
struct debug_reg debug; struct debug_reg debug;
struct thread_fp_state fp_state; struct thread_fp_state fp_state;
struct thread_fp_state *fp_save_area; struct thread_fp_state *fp_save_area;

View file

@ -40,7 +40,7 @@
#define _PAGE_U1 0x010000 #define _PAGE_U1 0x010000
#define _PAGE_U0 0x020000 #define _PAGE_U0 0x020000
#define _PAGE_ACCESSED 0x040000 #define _PAGE_ACCESSED 0x040000
#define _PAGE_LENDIAN 0x080000 #define _PAGE_ENDIAN 0x080000
#define _PAGE_GUARDED 0x100000 #define _PAGE_GUARDED 0x100000
#define _PAGE_COHERENT 0x200000 /* M: enforce memory coherence */ #define _PAGE_COHERENT 0x200000 /* M: enforce memory coherence */
#define _PAGE_NO_CACHE 0x400000 /* I: cache inhibit */ #define _PAGE_NO_CACHE 0x400000 /* I: cache inhibit */

View file

@ -248,6 +248,7 @@
#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */ #define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */ #define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */ #define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
#define SPRN_TBU40 0x11E /* Timebase upper 40 bits (hyper, R/W) */
#define SPRN_SPURR 0x134 /* Scaled PURR */ #define SPRN_SPURR 0x134 /* Scaled PURR */
#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */ #define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */
#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */ #define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */
@ -288,6 +289,7 @@
#define LPCR_ISL (1ul << (63-2)) #define LPCR_ISL (1ul << (63-2))
#define LPCR_VC_SH (63-2) #define LPCR_VC_SH (63-2)
#define LPCR_DPFD_SH (63-11) #define LPCR_DPFD_SH (63-11)
#define LPCR_DPFD (7ul << LPCR_DPFD_SH)
#define LPCR_VRMASD (0x1ful << (63-16)) #define LPCR_VRMASD (0x1ful << (63-16))
#define LPCR_VRMA_L (1ul << (63-12)) #define LPCR_VRMA_L (1ul << (63-12))
#define LPCR_VRMA_LP0 (1ul << (63-15)) #define LPCR_VRMA_LP0 (1ul << (63-15))
@ -304,6 +306,7 @@
#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */ #define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */
#define LPCR_MER 0x00000800 /* Mediated External Exception */ #define LPCR_MER 0x00000800 /* Mediated External Exception */
#define LPCR_MER_SH 11 #define LPCR_MER_SH 11
#define LPCR_TC 0x00000200 /* Translation control */
#define LPCR_LPES 0x0000000c #define LPCR_LPES 0x0000000c
#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */ #define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */
#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */ #define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */
@ -316,6 +319,10 @@
#define LPID_RSVD 0x3ff /* Reserved LPID for partn switching */ #define LPID_RSVD 0x3ff /* Reserved LPID for partn switching */
#define SPRN_HMER 0x150 /* Hardware m? error recovery */ #define SPRN_HMER 0x150 /* Hardware m? error recovery */
#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */ #define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */
#define SPRN_PCR 0x152 /* Processor compatibility register */
#define PCR_VEC_DIS (1ul << (63-0)) /* Vec. disable (bit NA since POWER8) */
#define PCR_VSX_DIS (1ul << (63-1)) /* VSX disable (bit NA since POWER8) */
#define PCR_ARCH_205 0x2 /* Architecture 2.05 */
#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */ #define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */ #define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */ #define SPRN_TLBVPNR 0x155 /* P7 TLB control register */
@ -425,6 +432,7 @@
#define HID4_RMLS2_SH (63 - 2) /* Real mode limit bottom 2 bits */ #define HID4_RMLS2_SH (63 - 2) /* Real mode limit bottom 2 bits */
#define HID4_LPID5_SH (63 - 6) /* partition ID bottom 4 bits */ #define HID4_LPID5_SH (63 - 6) /* partition ID bottom 4 bits */
#define HID4_RMOR_SH (63 - 22) /* real mode offset (16 bits) */ #define HID4_RMOR_SH (63 - 22) /* real mode offset (16 bits) */
#define HID4_RMOR (0xFFFFul << HID4_RMOR_SH)
#define HID4_LPES1 (1 << (63-57)) /* LPAR env. sel. bit 1 */ #define HID4_LPES1 (1 << (63-57)) /* LPAR env. sel. bit 1 */
#define HID4_RMLS0_SH (63 - 58) /* Real mode limit top bit */ #define HID4_RMLS0_SH (63 - 58) /* Real mode limit top bit */
#define HID4_LPID1_SH 0 /* partition ID top 2 bits */ #define HID4_LPID1_SH 0 /* partition ID top 2 bits */
@ -1107,6 +1115,13 @@
#define PVR_BE 0x0070 #define PVR_BE 0x0070
#define PVR_PA6T 0x0090 #define PVR_PA6T 0x0090
/* "Logical" PVR values defined in PAPR, representing architecture levels */
#define PVR_ARCH_204 0x0f000001
#define PVR_ARCH_205 0x0f000002
#define PVR_ARCH_206 0x0f000003
#define PVR_ARCH_206p 0x0f100003
#define PVR_ARCH_207 0x0f000004
/* Macros for setting and retrieving special purpose registers */ /* Macros for setting and retrieving special purpose registers */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define mfmsr() ({unsigned long rval; \ #define mfmsr() ({unsigned long rval; \

View file

@ -27,6 +27,7 @@
#define __KVM_HAVE_PPC_SMT #define __KVM_HAVE_PPC_SMT
#define __KVM_HAVE_IRQCHIP #define __KVM_HAVE_IRQCHIP
#define __KVM_HAVE_IRQ_LINE #define __KVM_HAVE_IRQ_LINE
#define __KVM_HAVE_GUEST_DEBUG
struct kvm_regs { struct kvm_regs {
__u64 pc; __u64 pc;
@ -269,7 +270,24 @@ struct kvm_fpu {
__u64 fpr[32]; __u64 fpr[32];
}; };
/*
* Defines for h/w breakpoint, watchpoint (read, write or both) and
* software breakpoint.
* These are used as "type" in KVM_SET_GUEST_DEBUG ioctl and "status"
* for KVM_DEBUG_EXIT.
*/
#define KVMPPC_DEBUG_NONE 0x0
#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1)
#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2)
#define KVMPPC_DEBUG_WATCH_READ (1UL << 3)
struct kvm_debug_exit_arch { struct kvm_debug_exit_arch {
__u64 address;
/*
* exiting to userspace because of h/w breakpoint, watchpoint
* (read, write or both) and software breakpoint.
*/
__u32 status;
__u32 reserved;
}; };
/* for KVM_SET_GUEST_DEBUG */ /* for KVM_SET_GUEST_DEBUG */
@ -281,10 +299,6 @@ struct kvm_guest_debug_arch {
* Type denotes h/w breakpoint, read watchpoint, write * Type denotes h/w breakpoint, read watchpoint, write
* watchpoint or watchpoint (both read and write). * watchpoint or watchpoint (both read and write).
*/ */
#define KVMPPC_DEBUG_NONE 0x0
#define KVMPPC_DEBUG_BREAKPOINT (1UL << 1)
#define KVMPPC_DEBUG_WATCH_WRITE (1UL << 2)
#define KVMPPC_DEBUG_WATCH_READ (1UL << 3)
__u32 type; __u32 type;
__u32 reserved; __u32 reserved;
} bp[16]; } bp[16];
@ -429,6 +443,11 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10) #define KVM_REG_PPC_MMCR0 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x10)
#define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11) #define KVM_REG_PPC_MMCR1 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x11)
#define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12) #define KVM_REG_PPC_MMCRA (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x12)
#define KVM_REG_PPC_MMCR2 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x13)
#define KVM_REG_PPC_MMCRS (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x14)
#define KVM_REG_PPC_SIAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x15)
#define KVM_REG_PPC_SDAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x16)
#define KVM_REG_PPC_SIER (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x17)
#define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18) #define KVM_REG_PPC_PMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x18)
#define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19) #define KVM_REG_PPC_PMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x19)
@ -499,6 +518,65 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a) #define KVM_REG_PPC_TLB3PS (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9a)
#define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b) #define KVM_REG_PPC_EPTCFG (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9b)
/* Timebase offset */
#define KVM_REG_PPC_TB_OFFSET (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9c)
/* POWER8 registers */
#define KVM_REG_PPC_SPMC1 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9d)
#define KVM_REG_PPC_SPMC2 (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x9e)
#define KVM_REG_PPC_IAMR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x9f)
#define KVM_REG_PPC_TFHAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa0)
#define KVM_REG_PPC_TFIAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa1)
#define KVM_REG_PPC_TEXASR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa2)
#define KVM_REG_PPC_FSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa3)
#define KVM_REG_PPC_PSPB (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xa4)
#define KVM_REG_PPC_EBBHR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa5)
#define KVM_REG_PPC_EBBRR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa6)
#define KVM_REG_PPC_BESCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa7)
#define KVM_REG_PPC_TAR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa8)
#define KVM_REG_PPC_DPDES (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xa9)
#define KVM_REG_PPC_DAWR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xaa)
#define KVM_REG_PPC_DAWRX (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xab)
#define KVM_REG_PPC_CIABR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xac)
#define KVM_REG_PPC_IC (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xad)
#define KVM_REG_PPC_VTB (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xae)
#define KVM_REG_PPC_CSIGR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xaf)
#define KVM_REG_PPC_TACR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb0)
#define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1)
#define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2)
#define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3)
#define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
#define KVM_REG_PPC_PPR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
/* Architecture compatibility level */
#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
/* Transactional Memory checkpointed state:
* This is all GPRs, all VSX regs and a subset of SPRs
*/
#define KVM_REG_PPC_TM (KVM_REG_PPC | 0x80000000)
/* TM GPRs */
#define KVM_REG_PPC_TM_GPR0 (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0)
#define KVM_REG_PPC_TM_GPR(n) (KVM_REG_PPC_TM_GPR0 + (n))
#define KVM_REG_PPC_TM_GPR31 (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x1f)
/* TM VSX */
#define KVM_REG_PPC_TM_VSR0 (KVM_REG_PPC_TM | KVM_REG_SIZE_U128 | 0x20)
#define KVM_REG_PPC_TM_VSR(n) (KVM_REG_PPC_TM_VSR0 + (n))
#define KVM_REG_PPC_TM_VSR63 (KVM_REG_PPC_TM | KVM_REG_SIZE_U128 | 0x5f)
/* TM SPRS */
#define KVM_REG_PPC_TM_CR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x60)
#define KVM_REG_PPC_TM_LR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x61)
#define KVM_REG_PPC_TM_CTR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x62)
#define KVM_REG_PPC_TM_FPSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x63)
#define KVM_REG_PPC_TM_AMR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x64)
#define KVM_REG_PPC_TM_PPR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x65)
#define KVM_REG_PPC_TM_VRSAVE (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x66)
#define KVM_REG_PPC_TM_VSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67)
#define KVM_REG_PPC_TM_DSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68)
#define KVM_REG_PPC_TM_TAR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69)
/* PPC64 eXternal Interrupt Controller Specification */ /* PPC64 eXternal Interrupt Controller Specification */
#define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ #define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */

View file

@ -439,7 +439,7 @@ int main(void)
DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr)); DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr)); DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc)); DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.shregs.msr)); DEFINE(VCPU_MSR, offsetof(struct kvm_vcpu, arch.shregs.msr));
DEFINE(VCPU_SRR0, offsetof(struct kvm_vcpu, arch.shregs.srr0)); DEFINE(VCPU_SRR0, offsetof(struct kvm_vcpu, arch.shregs.srr0));
DEFINE(VCPU_SRR1, offsetof(struct kvm_vcpu, arch.shregs.srr1)); DEFINE(VCPU_SRR1, offsetof(struct kvm_vcpu, arch.shregs.srr1));
@ -470,7 +470,7 @@ int main(void)
DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid)); DEFINE(KVM_LPID, offsetof(struct kvm, arch.lpid));
/* book3s */ /* book3s */
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
DEFINE(KVM_SDR1, offsetof(struct kvm, arch.sdr1)); DEFINE(KVM_SDR1, offsetof(struct kvm, arch.sdr1));
DEFINE(KVM_HOST_LPID, offsetof(struct kvm, arch.host_lpid)); DEFINE(KVM_HOST_LPID, offsetof(struct kvm, arch.host_lpid));
DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr)); DEFINE(KVM_HOST_LPCR, offsetof(struct kvm, arch.host_lpcr));
@ -502,6 +502,8 @@ int main(void)
DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded)); DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded));
DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr)); DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr));
DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc)); DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc));
DEFINE(VCPU_SIAR, offsetof(struct kvm_vcpu, arch.siar));
DEFINE(VCPU_SDAR, offsetof(struct kvm_vcpu, arch.sdar));
DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb)); DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb));
DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max)); DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max));
DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr)); DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
@ -511,18 +513,22 @@ int main(void)
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap)); DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid)); DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid));
DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar)); DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1));
DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count)); DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count));
DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count)); DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count));
DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest)); DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads)); DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
DEFINE(VCPU_SVCPU, offsetof(struct kvmppc_vcpu_book3s, shadow_vcpu) - DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
offsetof(struct kvmppc_vcpu_book3s, vcpu)); DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr));
DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige)); DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv)); DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb)); DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
#ifdef CONFIG_KVM_BOOK3S_PR #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
DEFINE(PACA_SVCPU, offsetof(struct paca_struct, shadow_vcpu));
# define SVCPU_FIELD(x, f) DEFINE(x, offsetof(struct paca_struct, shadow_vcpu.f)) # define SVCPU_FIELD(x, f) DEFINE(x, offsetof(struct paca_struct, shadow_vcpu.f))
#else #else
# define SVCPU_FIELD(x, f) # define SVCPU_FIELD(x, f)
@ -574,7 +580,7 @@ int main(void)
HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5); HSTATE_FIELD(HSTATE_RESTORE_HID5, restore_hid5);
HSTATE_FIELD(HSTATE_NAPPING, napping); HSTATE_FIELD(HSTATE_NAPPING, napping);
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
HSTATE_FIELD(HSTATE_HWTHREAD_REQ, hwthread_req); HSTATE_FIELD(HSTATE_HWTHREAD_REQ, hwthread_req);
HSTATE_FIELD(HSTATE_HWTHREAD_STATE, hwthread_state); HSTATE_FIELD(HSTATE_HWTHREAD_STATE, hwthread_state);
HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu); HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu);
@ -590,10 +596,11 @@ int main(void)
HSTATE_FIELD(HSTATE_DABR, dabr); HSTATE_FIELD(HSTATE_DABR, dabr);
HSTATE_FIELD(HSTATE_DECEXP, dec_expires); HSTATE_FIELD(HSTATE_DECEXP, dec_expires);
DEFINE(IPI_PRIORITY, IPI_PRIORITY); DEFINE(IPI_PRIORITY, IPI_PRIORITY);
#endif /* CONFIG_KVM_BOOK3S_64_HV */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
HSTATE_FIELD(HSTATE_CFAR, cfar); HSTATE_FIELD(HSTATE_CFAR, cfar);
HSTATE_FIELD(HSTATE_PPR, ppr);
#endif /* CONFIG_PPC_BOOK3S_64 */ #endif /* CONFIG_PPC_BOOK3S_64 */
#else /* CONFIG_PPC_BOOK3S */ #else /* CONFIG_PPC_BOOK3S */

View file

@ -126,7 +126,7 @@ BEGIN_FTR_SECTION
bgt cr1,. bgt cr1,.
GET_PACA(r13) GET_PACA(r13)
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
li r0,KVM_HWTHREAD_IN_KERNEL li r0,KVM_HWTHREAD_IN_KERNEL
stb r0,HSTATE_HWTHREAD_STATE(r13) stb r0,HSTATE_HWTHREAD_STATE(r13)
/* Order setting hwthread_state vs. testing hwthread_req */ /* Order setting hwthread_state vs. testing hwthread_req */
@ -425,7 +425,7 @@ data_access_check_stab:
mfspr r9,SPRN_DSISR mfspr r9,SPRN_DSISR
srdi r10,r10,60 srdi r10,r10,60
rlwimi r10,r9,16,0x20 rlwimi r10,r9,16,0x20
#ifdef CONFIG_KVM_BOOK3S_PR #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
lbz r9,HSTATE_IN_GUEST(r13) lbz r9,HSTATE_IN_GUEST(r13)
rlwimi r10,r9,8,0x300 rlwimi r10,r9,8,0x300
#endif #endif
@ -650,6 +650,32 @@ slb_miss_user_pseries:
b . /* prevent spec. execution */ b . /* prevent spec. execution */
#endif /* __DISABLED__ */ #endif /* __DISABLED__ */
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
kvmppc_skip_interrupt:
/*
* Here all GPRs are unchanged from when the interrupt happened
* except for r13, which is saved in SPRG_SCRATCH0.
*/
mfspr r13, SPRN_SRR0
addi r13, r13, 4
mtspr SPRN_SRR0, r13
GET_SCRATCH0(r13)
rfid
b .
kvmppc_skip_Hinterrupt:
/*
* Here all GPRs are unchanged from when the interrupt happened
* except for r13, which is saved in SPRG_SCRATCH0.
*/
mfspr r13, SPRN_HSRR0
addi r13, r13, 4
mtspr SPRN_HSRR0, r13
GET_SCRATCH0(r13)
hrfid
b .
#endif
/* /*
* Code from here down to __end_handlers is invoked from the * Code from here down to __end_handlers is invoked from the
* exception prologs above. Because the prologs assemble the * exception prologs above. Because the prologs assemble the

View file

@ -84,7 +84,7 @@ _GLOBAL(power7_nap)
std r9,_MSR(r1) std r9,_MSR(r1)
std r1,PACAR1(r13) std r1,PACAR1(r13)
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
/* Tell KVM we're napping */ /* Tell KVM we're napping */
li r4,KVM_HWTHREAD_IN_NAP li r4,KVM_HWTHREAD_IN_NAP
stb r4,HSTATE_HWTHREAD_STATE(r13) stb r4,HSTATE_HWTHREAD_STATE(r13)

View file

@ -1529,7 +1529,7 @@ static void handle_debug(struct pt_regs *regs, unsigned long debug_status)
* back on or not. * back on or not.
*/ */
if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0, if (DBCR_ACTIVE_EVENTS(current->thread.debug.dbcr0,
current->thread.debug.dbcr1)) current->thread.debug.dbcr1))
regs->msr |= MSR_DE; regs->msr |= MSR_DE;
else else
/* Make sure the IDM flag is off */ /* Make sure the IDM flag is off */

View file

@ -31,13 +31,13 @@
#include "44x_tlb.h" #include "44x_tlb.h"
#include "booke.h" #include "booke.h"
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) static void kvmppc_core_vcpu_load_44x(struct kvm_vcpu *vcpu, int cpu)
{ {
kvmppc_booke_vcpu_load(vcpu, cpu); kvmppc_booke_vcpu_load(vcpu, cpu);
kvmppc_44x_tlb_load(vcpu); kvmppc_44x_tlb_load(vcpu);
} }
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_put_44x(struct kvm_vcpu *vcpu)
{ {
kvmppc_44x_tlb_put(vcpu); kvmppc_44x_tlb_put(vcpu);
kvmppc_booke_vcpu_put(vcpu); kvmppc_booke_vcpu_put(vcpu);
@ -114,29 +114,32 @@ int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_get_sregs_44x(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
kvmppc_get_sregs_ivor(vcpu, sregs); return kvmppc_get_sregs_ivor(vcpu, sregs);
} }
int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_set_sregs_44x(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
return kvmppc_set_sregs_ivor(vcpu, sregs); return kvmppc_set_sregs_ivor(vcpu, sregs);
} }
int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_get_one_reg_44x(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
return -EINVAL; return -EINVAL;
} }
int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_set_one_reg_44x(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
return -EINVAL; return -EINVAL;
} }
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) static struct kvm_vcpu *kvmppc_core_vcpu_create_44x(struct kvm *kvm,
unsigned int id)
{ {
struct kvmppc_vcpu_44x *vcpu_44x; struct kvmppc_vcpu_44x *vcpu_44x;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
@ -167,7 +170,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
return ERR_PTR(err); return ERR_PTR(err);
} }
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_free_44x(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
@ -176,28 +179,53 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu_44x); kmem_cache_free(kvm_vcpu_cache, vcpu_44x);
} }
int kvmppc_core_init_vm(struct kvm *kvm) static int kvmppc_core_init_vm_44x(struct kvm *kvm)
{ {
return 0; return 0;
} }
void kvmppc_core_destroy_vm(struct kvm *kvm) static void kvmppc_core_destroy_vm_44x(struct kvm *kvm)
{ {
} }
static struct kvmppc_ops kvm_ops_44x = {
.get_sregs = kvmppc_core_get_sregs_44x,
.set_sregs = kvmppc_core_set_sregs_44x,
.get_one_reg = kvmppc_get_one_reg_44x,
.set_one_reg = kvmppc_set_one_reg_44x,
.vcpu_load = kvmppc_core_vcpu_load_44x,
.vcpu_put = kvmppc_core_vcpu_put_44x,
.vcpu_create = kvmppc_core_vcpu_create_44x,
.vcpu_free = kvmppc_core_vcpu_free_44x,
.mmu_destroy = kvmppc_mmu_destroy_44x,
.init_vm = kvmppc_core_init_vm_44x,
.destroy_vm = kvmppc_core_destroy_vm_44x,
.emulate_op = kvmppc_core_emulate_op_44x,
.emulate_mtspr = kvmppc_core_emulate_mtspr_44x,
.emulate_mfspr = kvmppc_core_emulate_mfspr_44x,
};
static int __init kvmppc_44x_init(void) static int __init kvmppc_44x_init(void)
{ {
int r; int r;
r = kvmppc_booke_init(); r = kvmppc_booke_init();
if (r) if (r)
return r; goto err_out;
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), 0, THIS_MODULE); r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_44x), 0, THIS_MODULE);
if (r)
goto err_out;
kvm_ops_44x.owner = THIS_MODULE;
kvmppc_pr_ops = &kvm_ops_44x;
err_out:
return r;
} }
static void __exit kvmppc_44x_exit(void) static void __exit kvmppc_44x_exit(void)
{ {
kvmppc_pr_ops = NULL;
kvmppc_booke_exit(); kvmppc_booke_exit();
} }

View file

@ -91,8 +91,8 @@ static int emulate_mfdcr(struct kvm_vcpu *vcpu, int rt, int dcrn)
return EMULATE_DONE; return EMULATE_DONE;
} }
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, int kvmppc_core_emulate_op_44x(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance) unsigned int inst, int *advance)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
int dcrn = get_dcrn(inst); int dcrn = get_dcrn(inst);
@ -152,7 +152,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
return emulated; return emulated;
} }
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) int kvmppc_core_emulate_mtspr_44x(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
@ -172,7 +172,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
return emulated; return emulated;
} }
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) int kvmppc_core_emulate_mfspr_44x(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;

View file

@ -268,7 +268,7 @@ static void kvmppc_44x_shadow_release(struct kvmppc_vcpu_44x *vcpu_44x,
trace_kvm_stlb_inval(stlb_index); trace_kvm_stlb_inval(stlb_index);
} }
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy_44x(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu); struct kvmppc_vcpu_44x *vcpu_44x = to_44x(vcpu);
int i; int i;

View file

@ -35,17 +35,20 @@ config KVM_BOOK3S_64_HANDLER
bool bool
select KVM_BOOK3S_HANDLER select KVM_BOOK3S_HANDLER
config KVM_BOOK3S_PR config KVM_BOOK3S_PR_POSSIBLE
bool bool
select KVM_MMIO select KVM_MMIO
select MMU_NOTIFIER select MMU_NOTIFIER
config KVM_BOOK3S_HV_POSSIBLE
bool
config KVM_BOOK3S_32 config KVM_BOOK3S_32
tristate "KVM support for PowerPC book3s_32 processors" tristate "KVM support for PowerPC book3s_32 processors"
depends on PPC_BOOK3S_32 && !SMP && !PTE_64BIT depends on PPC_BOOK3S_32 && !SMP && !PTE_64BIT
select KVM select KVM
select KVM_BOOK3S_32_HANDLER select KVM_BOOK3S_32_HANDLER
select KVM_BOOK3S_PR select KVM_BOOK3S_PR_POSSIBLE
---help--- ---help---
Support running unmodified book3s_32 guest kernels Support running unmodified book3s_32 guest kernels
in virtual machines on book3s_32 host processors. in virtual machines on book3s_32 host processors.
@ -60,6 +63,7 @@ config KVM_BOOK3S_64
depends on PPC_BOOK3S_64 depends on PPC_BOOK3S_64
select KVM_BOOK3S_64_HANDLER select KVM_BOOK3S_64_HANDLER
select KVM select KVM
select KVM_BOOK3S_PR_POSSIBLE if !KVM_BOOK3S_HV_POSSIBLE
---help--- ---help---
Support running unmodified book3s_64 and book3s_32 guest kernels Support running unmodified book3s_64 and book3s_32 guest kernels
in virtual machines on book3s_64 host processors. in virtual machines on book3s_64 host processors.
@ -70,8 +74,9 @@ config KVM_BOOK3S_64
If unsure, say N. If unsure, say N.
config KVM_BOOK3S_64_HV config KVM_BOOK3S_64_HV
bool "KVM support for POWER7 and PPC970 using hypervisor mode in host" tristate "KVM support for POWER7 and PPC970 using hypervisor mode in host"
depends on KVM_BOOK3S_64 depends on KVM_BOOK3S_64
select KVM_BOOK3S_HV_POSSIBLE
select MMU_NOTIFIER select MMU_NOTIFIER
select CMA select CMA
---help--- ---help---
@ -90,9 +95,20 @@ config KVM_BOOK3S_64_HV
If unsure, say N. If unsure, say N.
config KVM_BOOK3S_64_PR config KVM_BOOK3S_64_PR
def_bool y tristate "KVM support without using hypervisor mode in host"
depends on KVM_BOOK3S_64 && !KVM_BOOK3S_64_HV depends on KVM_BOOK3S_64
select KVM_BOOK3S_PR select KVM_BOOK3S_PR_POSSIBLE
---help---
Support running guest kernels in virtual machines on processors
without using hypervisor mode in the host, by running the
guest in user mode (problem state) and emulating all
privileged instructions and registers.
This is not as fast as using hypervisor mode, but works on
machines where hypervisor mode is not available or not usable,
and can emulate processors that are different from the host
processor, including emulating 32-bit processors on a 64-bit
host.
config KVM_BOOKE_HV config KVM_BOOKE_HV
bool bool

View file

@ -53,41 +53,51 @@ kvm-e500mc-objs := \
e500_emulate.o e500_emulate.o
kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs) kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs)
kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) := \
$(KVM)/coalesced_mmio.o \ book3s_64_vio_hv.o
kvm-pr-y := \
fpu.o \ fpu.o \
book3s_paired_singles.o \ book3s_paired_singles.o \
book3s_pr.o \ book3s_pr.o \
book3s_pr_papr.o \ book3s_pr_papr.o \
book3s_64_vio_hv.o \
book3s_emulate.o \ book3s_emulate.o \
book3s_interrupts.o \ book3s_interrupts.o \
book3s_mmu_hpte.o \ book3s_mmu_hpte.o \
book3s_64_mmu_host.o \ book3s_64_mmu_host.o \
book3s_64_mmu.o \ book3s_64_mmu.o \
book3s_32_mmu.o book3s_32_mmu.o
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \
book3s_rmhandlers.o
kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
kvm-book3s_64-module-objs := \
$(KVM)/coalesced_mmio.o
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
book3s_rmhandlers.o
endif
kvm-hv-y += \
book3s_hv.o \ book3s_hv.o \
book3s_hv_interrupts.o \ book3s_hv_interrupts.o \
book3s_64_mmu_hv.o book3s_64_mmu_hv.o
kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \ kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \
book3s_hv_rm_xics.o book3s_hv_rm_xics.o
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
book3s_hv_rmhandlers.o \ book3s_hv_rmhandlers.o \
book3s_hv_rm_mmu.o \ book3s_hv_rm_mmu.o \
book3s_64_vio_hv.o \
book3s_hv_ras.o \ book3s_hv_ras.o \
book3s_hv_builtin.o \ book3s_hv_builtin.o \
book3s_hv_cma.o \ book3s_hv_cma.o \
$(kvm-book3s_64-builtin-xics-objs-y) $(kvm-book3s_64-builtin-xics-objs-y)
endif
kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
book3s_xics.o book3s_xics.o
kvm-book3s_64-module-objs := \ kvm-book3s_64-module-objs += \
$(KVM)/kvm_main.o \ $(KVM)/kvm_main.o \
$(KVM)/eventfd.o \ $(KVM)/eventfd.o \
powerpc.o \ powerpc.o \
@ -123,4 +133,7 @@ obj-$(CONFIG_KVM_E500MC) += kvm.o
obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o
obj-$(CONFIG_KVM_BOOK3S_32) += kvm.o obj-$(CONFIG_KVM_BOOK3S_32) += kvm.o
obj-$(CONFIG_KVM_BOOK3S_64_PR) += kvm-pr.o
obj-$(CONFIG_KVM_BOOK3S_64_HV) += kvm-hv.o
obj-y += $(kvm-book3s_64-builtin-objs-y) obj-y += $(kvm-book3s_64-builtin-objs-y)

View file

@ -34,6 +34,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include "book3s.h"
#include "trace.h" #include "trace.h"
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
@ -69,6 +70,50 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu)
{ {
} }
static inline unsigned long kvmppc_interrupt_offset(struct kvm_vcpu *vcpu)
{
if (!is_kvmppc_hv_enabled(vcpu->kvm))
return to_book3s(vcpu)->hior;
return 0;
}
static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu,
unsigned long pending_now, unsigned long old_pending)
{
if (is_kvmppc_hv_enabled(vcpu->kvm))
return;
if (pending_now)
vcpu->arch.shared->int_pending = 1;
else if (old_pending)
vcpu->arch.shared->int_pending = 0;
}
static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu)
{
ulong crit_raw;
ulong crit_r1;
bool crit;
if (is_kvmppc_hv_enabled(vcpu->kvm))
return false;
crit_raw = vcpu->arch.shared->critical;
crit_r1 = kvmppc_get_gpr(vcpu, 1);
/* Truncate crit indicators in 32 bit mode */
if (!(vcpu->arch.shared->msr & MSR_SF)) {
crit_raw &= 0xffffffff;
crit_r1 &= 0xffffffff;
}
/* Critical section when crit == r1 */
crit = (crit_raw == crit_r1);
/* ... and we're in supervisor mode */
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
return crit;
}
void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags)
{ {
vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu); vcpu->arch.shared->srr0 = kvmppc_get_pc(vcpu);
@ -126,28 +171,32 @@ void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec)
printk(KERN_INFO "Queueing interrupt %x\n", vec); printk(KERN_INFO "Queueing interrupt %x\n", vec);
#endif #endif
} }
EXPORT_SYMBOL_GPL(kvmppc_book3s_queue_irqprio);
void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags) void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags)
{ {
/* might as well deliver this straight away */ /* might as well deliver this straight away */
kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, flags); kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, flags);
} }
EXPORT_SYMBOL_GPL(kvmppc_core_queue_program);
void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu)
{ {
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER);
} }
EXPORT_SYMBOL_GPL(kvmppc_core_queue_dec);
int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
{ {
return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions); return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
} }
EXPORT_SYMBOL_GPL(kvmppc_core_pending_dec);
void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
{ {
kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER);
} }
EXPORT_SYMBOL_GPL(kvmppc_core_dequeue_dec);
void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq) struct kvm_interrupt *irq)
@ -285,8 +334,10 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(kvmppc_core_prepare_to_enter);
pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn) pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, bool writing,
bool *writable)
{ {
ulong mp_pa = vcpu->arch.magic_page_pa; ulong mp_pa = vcpu->arch.magic_page_pa;
@ -302,20 +353,23 @@ pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn)
pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT; pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
get_page(pfn_to_page(pfn)); get_page(pfn_to_page(pfn));
if (writable)
*writable = true;
return pfn; return pfn;
} }
return gfn_to_pfn(vcpu->kvm, gfn); return gfn_to_pfn_prot(vcpu->kvm, gfn, writing, writable);
} }
EXPORT_SYMBOL_GPL(kvmppc_gfn_to_pfn);
static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
struct kvmppc_pte *pte) bool iswrite, struct kvmppc_pte *pte)
{ {
int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR)); int relocated = (vcpu->arch.shared->msr & (data ? MSR_DR : MSR_IR));
int r; int r;
if (relocated) { if (relocated) {
r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data); r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data, iswrite);
} else { } else {
pte->eaddr = eaddr; pte->eaddr = eaddr;
pte->raddr = eaddr & KVM_PAM; pte->raddr = eaddr & KVM_PAM;
@ -361,7 +415,7 @@ int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
vcpu->stat.st++; vcpu->stat.st++;
if (kvmppc_xlate(vcpu, *eaddr, data, &pte)) if (kvmppc_xlate(vcpu, *eaddr, data, true, &pte))
return -ENOENT; return -ENOENT;
*eaddr = pte.raddr; *eaddr = pte.raddr;
@ -374,6 +428,7 @@ int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
return EMULATE_DONE; return EMULATE_DONE;
} }
EXPORT_SYMBOL_GPL(kvmppc_st);
int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
bool data) bool data)
@ -383,7 +438,7 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
vcpu->stat.ld++; vcpu->stat.ld++;
if (kvmppc_xlate(vcpu, *eaddr, data, &pte)) if (kvmppc_xlate(vcpu, *eaddr, data, false, &pte))
goto nopte; goto nopte;
*eaddr = pte.raddr; *eaddr = pte.raddr;
@ -404,6 +459,7 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
mmio: mmio:
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
EXPORT_SYMBOL_GPL(kvmppc_ld);
int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{ {
@ -419,6 +475,18 @@ void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu)
{ {
} }
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
return vcpu->kvm->arch.kvm_ops->get_sregs(vcpu, sregs);
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
return vcpu->kvm->arch.kvm_ops->set_sregs(vcpu, sregs);
}
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{ {
int i; int i;
@ -495,8 +563,7 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
if (size > sizeof(val)) if (size > sizeof(val))
return -EINVAL; return -EINVAL;
r = kvmppc_get_one_reg(vcpu, reg->id, &val); r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, reg->id, &val);
if (r == -EINVAL) { if (r == -EINVAL) {
r = 0; r = 0;
switch (reg->id) { switch (reg->id) {
@ -528,6 +595,9 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
} }
val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]); val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]);
break; break;
case KVM_REG_PPC_VRSAVE:
val = get_reg_val(reg->id, vcpu->arch.vrsave);
break;
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
case KVM_REG_PPC_DEBUG_INST: { case KVM_REG_PPC_DEBUG_INST: {
u32 opcode = INS_TW; u32 opcode = INS_TW;
@ -572,8 +642,7 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size)) if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size))
return -EFAULT; return -EFAULT;
r = kvmppc_set_one_reg(vcpu, reg->id, &val); r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, reg->id, &val);
if (r == -EINVAL) { if (r == -EINVAL) {
r = 0; r = 0;
switch (reg->id) { switch (reg->id) {
@ -605,6 +674,13 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
} }
vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val); vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val);
break; break;
case KVM_REG_PPC_VRSAVE:
if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
r = -ENXIO;
break;
}
vcpu->arch.vrsave = set_reg_val(reg->id, val);
break;
#endif /* CONFIG_ALTIVEC */ #endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_KVM_XICS #ifdef CONFIG_KVM_XICS
case KVM_REG_PPC_ICP_STATE: case KVM_REG_PPC_ICP_STATE:
@ -625,6 +701,27 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
return r; return r;
} }
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_load(vcpu, cpu);
}
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_put(vcpu);
}
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
{
vcpu->kvm->arch.kvm_ops->set_msr(vcpu, msr);
}
EXPORT_SYMBOL_GPL(kvmppc_set_msr);
int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
return vcpu->kvm->arch.kvm_ops->vcpu_run(kvm_run, vcpu);
}
int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
struct kvm_translation *tr) struct kvm_translation *tr)
{ {
@ -644,3 +741,141 @@ void kvmppc_decrementer_func(unsigned long data)
kvmppc_core_queue_dec(vcpu); kvmppc_core_queue_dec(vcpu);
kvm_vcpu_kick(vcpu); kvm_vcpu_kick(vcpu);
} }
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{
return kvm->arch.kvm_ops->vcpu_create(kvm, id);
}
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_free(vcpu);
}
int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
{
return vcpu->kvm->arch.kvm_ops->check_requests(vcpu);
}
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
{
return kvm->arch.kvm_ops->get_dirty_log(kvm, log);
}
void kvmppc_core_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
kvm->arch.kvm_ops->free_memslot(free, dont);
}
int kvmppc_core_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages)
{
return kvm->arch.kvm_ops->create_memslot(slot, npages);
}
void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
{
kvm->arch.kvm_ops->flush_memslot(kvm, memslot);
}
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_userspace_memory_region *mem)
{
return kvm->arch.kvm_ops->prepare_memory_region(kvm, memslot, mem);
}
void kvmppc_core_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old)
{
kvm->arch.kvm_ops->commit_memory_region(kvm, mem, old);
}
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
{
return kvm->arch.kvm_ops->unmap_hva(kvm, hva);
}
EXPORT_SYMBOL_GPL(kvm_unmap_hva);
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
{
return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end);
}
int kvm_age_hva(struct kvm *kvm, unsigned long hva)
{
return kvm->arch.kvm_ops->age_hva(kvm, hva);
}
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
{
return kvm->arch.kvm_ops->test_age_hva(kvm, hva);
}
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
{
kvm->arch.kvm_ops->set_spte_hva(kvm, hva, pte);
}
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->mmu_destroy(vcpu);
}
int kvmppc_core_init_vm(struct kvm *kvm)
{
#ifdef CONFIG_PPC64
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
INIT_LIST_HEAD(&kvm->arch.rtas_tokens);
#endif
return kvm->arch.kvm_ops->init_vm(kvm);
}
void kvmppc_core_destroy_vm(struct kvm *kvm)
{
kvm->arch.kvm_ops->destroy_vm(kvm);
#ifdef CONFIG_PPC64
kvmppc_rtas_tokens_free(kvm);
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
#endif
}
int kvmppc_core_check_processor_compat(void)
{
/*
* We always return 0 for book3s. We check
* for compatability while loading the HV
* or PR module
*/
return 0;
}
static int kvmppc_book3s_init(void)
{
int r;
r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
if (r)
return r;
#ifdef CONFIG_KVM_BOOK3S_32
r = kvmppc_book3s_init_pr();
#endif
return r;
}
static void kvmppc_book3s_exit(void)
{
#ifdef CONFIG_KVM_BOOK3S_32
kvmppc_book3s_exit_pr();
#endif
kvm_exit();
}
module_init(kvmppc_book3s_init);
module_exit(kvmppc_book3s_exit);

34
arch/powerpc/kvm/book3s.h Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright IBM Corporation, 2013
* Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License or (at your optional) any later version of the license.
*
*/
#ifndef __POWERPC_KVM_BOOK3S_H__
#define __POWERPC_KVM_BOOK3S_H__
extern void kvmppc_core_flush_memslot_hv(struct kvm *kvm,
struct kvm_memory_slot *memslot);
extern int kvm_unmap_hva_hv(struct kvm *kvm, unsigned long hva);
extern int kvm_unmap_hva_range_hv(struct kvm *kvm, unsigned long start,
unsigned long end);
extern int kvm_age_hva_hv(struct kvm *kvm, unsigned long hva);
extern int kvm_test_age_hva_hv(struct kvm *kvm, unsigned long hva);
extern void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte);
extern void kvmppc_mmu_destroy_pr(struct kvm_vcpu *vcpu);
extern int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance);
extern int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu,
int sprn, ulong spr_val);
extern int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu,
int sprn, ulong *spr_val);
extern int kvmppc_book3s_init_pr(void);
extern void kvmppc_book3s_exit_pr(void);
#endif

View file

@ -84,7 +84,8 @@ static inline bool sr_nx(u32 sr_raw)
} }
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data); struct kvmppc_pte *pte, bool data,
bool iswrite);
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
u64 *vsid); u64 *vsid);
@ -99,7 +100,7 @@ static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
u64 vsid; u64 vsid;
struct kvmppc_pte pte; struct kvmppc_pte pte;
if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data)) if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data, false))
return pte.vpage; return pte.vpage;
kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
@ -111,10 +112,11 @@ static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu)
kvmppc_set_msr(vcpu, 0); kvmppc_set_msr(vcpu, 0);
} }
static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvm_vcpu *vcpu,
u32 sre, gva_t eaddr, u32 sre, gva_t eaddr,
bool primary) bool primary)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
u32 page, hash, pteg, htabmask; u32 page, hash, pteg, htabmask;
hva_t r; hva_t r;
@ -132,7 +134,7 @@ static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3
kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg, kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg,
sr_vsid(sre)); sr_vsid(sre));
r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); r = gfn_to_hva(vcpu->kvm, pteg >> PAGE_SHIFT);
if (kvm_is_error_hva(r)) if (kvm_is_error_hva(r))
return r; return r;
return r | (pteg & ~PAGE_MASK); return r | (pteg & ~PAGE_MASK);
@ -145,7 +147,8 @@ static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary)
} }
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data) struct kvmppc_pte *pte, bool data,
bool iswrite)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_bat *bat; struct kvmppc_bat *bat;
@ -186,8 +189,7 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
printk(KERN_INFO "BAT is not readable!\n"); printk(KERN_INFO "BAT is not readable!\n");
continue; continue;
} }
if (!pte->may_write) { if (iswrite && !pte->may_write) {
/* let's treat r/o BATs as not-readable for now */
dprintk_pte("BAT is read-only!\n"); dprintk_pte("BAT is read-only!\n");
continue; continue;
} }
@ -201,9 +203,8 @@ static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data, struct kvmppc_pte *pte, bool data,
bool primary) bool iswrite, bool primary)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
u32 sre; u32 sre;
hva_t ptegp; hva_t ptegp;
u32 pteg[16]; u32 pteg[16];
@ -218,7 +219,7 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data);
ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu_book3s, sre, eaddr, primary); ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu, sre, eaddr, primary);
if (kvm_is_error_hva(ptegp)) { if (kvm_is_error_hva(ptegp)) {
printk(KERN_INFO "KVM: Invalid PTEG!\n"); printk(KERN_INFO "KVM: Invalid PTEG!\n");
goto no_page_found; goto no_page_found;
@ -258,9 +259,6 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
break; break;
} }
if ( !pte->may_read )
continue;
dprintk_pte("MMU: Found PTE -> %x %x - %x\n", dprintk_pte("MMU: Found PTE -> %x %x - %x\n",
pteg[i], pteg[i+1], pp); pteg[i], pteg[i+1], pp);
found = 1; found = 1;
@ -271,19 +269,23 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
/* Update PTE C and A bits, so the guest's swapper knows we used the /* Update PTE C and A bits, so the guest's swapper knows we used the
page */ page */
if (found) { if (found) {
u32 oldpte = pteg[i+1]; u32 pte_r = pteg[i+1];
char __user *addr = (char __user *) &pteg[i+1];
if (pte->may_read)
pteg[i+1] |= PTEG_FLAG_ACCESSED;
if (pte->may_write)
pteg[i+1] |= PTEG_FLAG_DIRTY;
else
dprintk_pte("KVM: Mapping read-only page!\n");
/* Write back into the PTEG */
if (pteg[i+1] != oldpte)
copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
/*
* Use single-byte writes to update the HPTE, to
* conform to what real hardware does.
*/
if (pte->may_read && !(pte_r & PTEG_FLAG_ACCESSED)) {
pte_r |= PTEG_FLAG_ACCESSED;
put_user(pte_r >> 8, addr + 2);
}
if (iswrite && pte->may_write && !(pte_r & PTEG_FLAG_DIRTY)) {
pte_r |= PTEG_FLAG_DIRTY;
put_user(pte_r, addr + 3);
}
if (!pte->may_read || (iswrite && !pte->may_write))
return -EPERM;
return 0; return 0;
} }
@ -302,12 +304,14 @@ static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr,
} }
static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *pte, bool data) struct kvmppc_pte *pte, bool data,
bool iswrite)
{ {
int r; int r;
ulong mp_ea = vcpu->arch.magic_page_ea; ulong mp_ea = vcpu->arch.magic_page_ea;
pte->eaddr = eaddr; pte->eaddr = eaddr;
pte->page_size = MMU_PAGE_4K;
/* Magic page override */ /* Magic page override */
if (unlikely(mp_ea) && if (unlikely(mp_ea) &&
@ -323,11 +327,13 @@ static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
return 0; return 0;
} }
r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data, iswrite);
if (r < 0) if (r < 0)
r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte,
data, iswrite, true);
if (r < 0) if (r < 0)
r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, false); r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte,
data, iswrite, false);
return r; return r;
} }
@ -347,7 +353,12 @@ static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum,
static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large) static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large)
{ {
kvmppc_mmu_pte_flush(vcpu, ea, 0x0FFFF000); int i;
struct kvm_vcpu *v;
/* flush this VA on all cpus */
kvm_for_each_vcpu(i, v, vcpu->kvm)
kvmppc_mmu_pte_flush(v, ea, 0x0FFFF000);
} }
static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,

View file

@ -138,7 +138,8 @@ static u32 *kvmppc_mmu_get_pteg(struct kvm_vcpu *vcpu, u32 vsid, u32 eaddr,
extern char etext[]; extern char etext[];
int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
bool iswrite)
{ {
pfn_t hpaddr; pfn_t hpaddr;
u64 vpn; u64 vpn;
@ -152,9 +153,11 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
bool evict = false; bool evict = false;
struct hpte_cache *pte; struct hpte_cache *pte;
int r = 0; int r = 0;
bool writable;
/* Get host physical address for gpa */ /* Get host physical address for gpa */
hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT); hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT,
iswrite, &writable);
if (is_error_noslot_pfn(hpaddr)) { if (is_error_noslot_pfn(hpaddr)) {
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n",
orig_pte->eaddr); orig_pte->eaddr);
@ -204,7 +207,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
(primary ? 0 : PTE_SEC); (primary ? 0 : PTE_SEC);
pteg1 = hpaddr | PTE_M | PTE_R | PTE_C; pteg1 = hpaddr | PTE_M | PTE_R | PTE_C;
if (orig_pte->may_write) { if (orig_pte->may_write && writable) {
pteg1 |= PP_RWRW; pteg1 |= PP_RWRW;
mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
} else { } else {
@ -259,6 +262,11 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
return r; return r;
} }
void kvmppc_mmu_unmap_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
{
kvmppc_mmu_pte_vflush(vcpu, pte->vpage, 0xfffffffffULL);
}
static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
{ {
struct kvmppc_sid_map *map; struct kvmppc_sid_map *map;
@ -341,7 +349,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
svcpu_put(svcpu); svcpu_put(svcpu);
} }
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy_pr(struct kvm_vcpu *vcpu)
{ {
int i; int i;

View file

@ -107,9 +107,20 @@ static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
return kvmppc_slb_calc_vpn(slb, eaddr); return kvmppc_slb_calc_vpn(slb, eaddr);
} }
static int mmu_pagesize(int mmu_pg)
{
switch (mmu_pg) {
case MMU_PAGE_64K:
return 16;
case MMU_PAGE_16M:
return 24;
}
return 12;
}
static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe) static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe)
{ {
return slbe->large ? 24 : 12; return mmu_pagesize(slbe->base_page_size);
} }
static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr) static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr)
@ -119,11 +130,11 @@ static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr)
return ((eaddr & kvmppc_slb_offset_mask(slbe)) >> p); return ((eaddr & kvmppc_slb_offset_mask(slbe)) >> p);
} }
static hva_t kvmppc_mmu_book3s_64_get_pteg( static hva_t kvmppc_mmu_book3s_64_get_pteg(struct kvm_vcpu *vcpu,
struct kvmppc_vcpu_book3s *vcpu_book3s,
struct kvmppc_slb *slbe, gva_t eaddr, struct kvmppc_slb *slbe, gva_t eaddr,
bool second) bool second)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
u64 hash, pteg, htabsize; u64 hash, pteg, htabsize;
u32 ssize; u32 ssize;
hva_t r; hva_t r;
@ -148,10 +159,10 @@ static hva_t kvmppc_mmu_book3s_64_get_pteg(
/* When running a PAPR guest, SDR1 contains a HVA address instead /* When running a PAPR guest, SDR1 contains a HVA address instead
of a GPA */ of a GPA */
if (vcpu_book3s->vcpu.arch.papr_enabled) if (vcpu->arch.papr_enabled)
r = pteg; r = pteg;
else else
r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); r = gfn_to_hva(vcpu->kvm, pteg >> PAGE_SHIFT);
if (kvm_is_error_hva(r)) if (kvm_is_error_hva(r))
return r; return r;
@ -166,18 +177,38 @@ static u64 kvmppc_mmu_book3s_64_get_avpn(struct kvmppc_slb *slbe, gva_t eaddr)
avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr); avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr);
avpn |= slbe->vsid << (kvmppc_slb_sid_shift(slbe) - p); avpn |= slbe->vsid << (kvmppc_slb_sid_shift(slbe) - p);
if (p < 24) if (p < 16)
avpn >>= ((80 - p) - 56) - 8; avpn >>= ((80 - p) - 56) - 8; /* 16 - p */
else else
avpn <<= 8; avpn <<= p - 16;
return avpn; return avpn;
} }
static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, /*
struct kvmppc_pte *gpte, bool data) * Return page size encoded in the second word of a HPTE, or
* -1 for an invalid encoding for the base page size indicated by
* the SLB entry. This doesn't handle mixed pagesize segments yet.
*/
static int decode_pagesize(struct kvmppc_slb *slbe, u64 r)
{
switch (slbe->base_page_size) {
case MMU_PAGE_64K:
if ((r & 0xf000) == 0x1000)
return MMU_PAGE_64K;
break;
case MMU_PAGE_16M:
if ((r & 0xff000) == 0)
return MMU_PAGE_16M;
break;
}
return -1;
}
static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *gpte, bool data,
bool iswrite)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
struct kvmppc_slb *slbe; struct kvmppc_slb *slbe;
hva_t ptegp; hva_t ptegp;
u64 pteg[16]; u64 pteg[16];
@ -189,6 +220,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
u8 pp, key = 0; u8 pp, key = 0;
bool found = false; bool found = false;
bool second = false; bool second = false;
int pgsize;
ulong mp_ea = vcpu->arch.magic_page_ea; ulong mp_ea = vcpu->arch.magic_page_ea;
/* Magic page override */ /* Magic page override */
@ -202,6 +234,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
gpte->may_execute = true; gpte->may_execute = true;
gpte->may_read = true; gpte->may_read = true;
gpte->may_write = true; gpte->may_write = true;
gpte->page_size = MMU_PAGE_4K;
return 0; return 0;
} }
@ -222,8 +255,12 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
v_mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_LARGE | HPTE_V_VALID | v_mask = SLB_VSID_B | HPTE_V_AVPN | HPTE_V_LARGE | HPTE_V_VALID |
HPTE_V_SECONDARY; HPTE_V_SECONDARY;
pgsize = slbe->large ? MMU_PAGE_16M : MMU_PAGE_4K;
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
do_second: do_second:
ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second); ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu, slbe, eaddr, second);
if (kvm_is_error_hva(ptegp)) if (kvm_is_error_hva(ptegp))
goto no_page_found; goto no_page_found;
@ -240,6 +277,13 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
for (i=0; i<16; i+=2) { for (i=0; i<16; i+=2) {
/* Check all relevant fields of 1st dword */ /* Check all relevant fields of 1st dword */
if ((pteg[i] & v_mask) == v_val) { if ((pteg[i] & v_mask) == v_val) {
/* If large page bit is set, check pgsize encoding */
if (slbe->large &&
(vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE)) {
pgsize = decode_pagesize(slbe, pteg[i+1]);
if (pgsize < 0)
continue;
}
found = true; found = true;
break; break;
} }
@ -256,13 +300,15 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
v = pteg[i]; v = pteg[i];
r = pteg[i+1]; r = pteg[i+1];
pp = (r & HPTE_R_PP) | key; pp = (r & HPTE_R_PP) | key;
eaddr_mask = 0xFFF; if (r & HPTE_R_PP0)
pp |= 8;
gpte->eaddr = eaddr; gpte->eaddr = eaddr;
gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data); gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, eaddr, data);
if (slbe->large)
eaddr_mask = 0xFFFFFF; eaddr_mask = (1ull << mmu_pagesize(pgsize)) - 1;
gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask); gpte->raddr = (r & HPTE_R_RPN & ~eaddr_mask) | (eaddr & eaddr_mask);
gpte->page_size = pgsize;
gpte->may_execute = ((r & HPTE_R_N) ? false : true); gpte->may_execute = ((r & HPTE_R_N) ? false : true);
gpte->may_read = false; gpte->may_read = false;
gpte->may_write = false; gpte->may_write = false;
@ -277,6 +323,7 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
case 3: case 3:
case 5: case 5:
case 7: case 7:
case 10:
gpte->may_read = true; gpte->may_read = true;
break; break;
} }
@ -287,30 +334,37 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
/* Update PTE R and C bits, so the guest's swapper knows we used the /* Update PTE R and C bits, so the guest's swapper knows we used the
* page */ * page */
if (gpte->may_read) { if (gpte->may_read && !(r & HPTE_R_R)) {
/* Set the accessed flag */ /*
* Set the accessed flag.
* We have to write this back with a single byte write
* because another vcpu may be accessing this on
* non-PAPR platforms such as mac99, and this is
* what real hardware does.
*/
char __user *addr = (char __user *) &pteg[i+1];
r |= HPTE_R_R; r |= HPTE_R_R;
put_user(r >> 8, addr + 6);
} }
if (data && gpte->may_write) { if (iswrite && gpte->may_write && !(r & HPTE_R_C)) {
/* Set the dirty flag -- XXX even if not writing */ /* Set the dirty flag */
/* Use a single byte write */
char __user *addr = (char __user *) &pteg[i+1];
r |= HPTE_R_C; r |= HPTE_R_C;
put_user(r, addr + 7);
} }
/* Write back into the PTEG */ mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
if (pteg[i+1] != r) {
pteg[i+1] = r;
copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
}
if (!gpte->may_read) if (!gpte->may_read || (iswrite && !gpte->may_write))
return -EPERM; return -EPERM;
return 0; return 0;
no_page_found: no_page_found:
mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
return -ENOENT; return -ENOENT;
no_seg_found: no_seg_found:
dprintk("KVM MMU: Trigger segment fault\n"); dprintk("KVM MMU: Trigger segment fault\n");
return -EINVAL; return -EINVAL;
} }
@ -345,6 +399,21 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb)
slbe->nx = (rs & SLB_VSID_N) ? 1 : 0; slbe->nx = (rs & SLB_VSID_N) ? 1 : 0;
slbe->class = (rs & SLB_VSID_C) ? 1 : 0; slbe->class = (rs & SLB_VSID_C) ? 1 : 0;
slbe->base_page_size = MMU_PAGE_4K;
if (slbe->large) {
if (vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE) {
switch (rs & SLB_VSID_LP) {
case SLB_VSID_LP_00:
slbe->base_page_size = MMU_PAGE_16M;
break;
case SLB_VSID_LP_01:
slbe->base_page_size = MMU_PAGE_64K;
break;
}
} else
slbe->base_page_size = MMU_PAGE_16M;
}
slbe->orige = rb & (ESID_MASK | SLB_ESID_V); slbe->orige = rb & (ESID_MASK | SLB_ESID_V);
slbe->origv = rs; slbe->origv = rs;
@ -460,14 +529,45 @@ static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va,
bool large) bool large)
{ {
u64 mask = 0xFFFFFFFFFULL; u64 mask = 0xFFFFFFFFFULL;
long i;
struct kvm_vcpu *v;
dprintk("KVM MMU: tlbie(0x%lx)\n", va); dprintk("KVM MMU: tlbie(0x%lx)\n", va);
if (large) /*
mask = 0xFFFFFF000ULL; * The tlbie instruction changed behaviour starting with
kvmppc_mmu_pte_vflush(vcpu, va >> 12, mask); * POWER6. POWER6 and later don't have the large page flag
* in the instruction but in the RB value, along with bits
* indicating page and segment sizes.
*/
if (vcpu->arch.hflags & BOOK3S_HFLAG_NEW_TLBIE) {
/* POWER6 or later */
if (va & 1) { /* L bit */
if ((va & 0xf000) == 0x1000)
mask = 0xFFFFFFFF0ULL; /* 64k page */
else
mask = 0xFFFFFF000ULL; /* 16M page */
}
} else {
/* older processors, e.g. PPC970 */
if (large)
mask = 0xFFFFFF000ULL;
}
/* flush this VA on all vcpus */
kvm_for_each_vcpu(i, v, vcpu->kvm)
kvmppc_mmu_pte_vflush(v, va >> 12, mask);
} }
#ifdef CONFIG_PPC_64K_PAGES
static int segment_contains_magic_page(struct kvm_vcpu *vcpu, ulong esid)
{
ulong mp_ea = vcpu->arch.magic_page_ea;
return mp_ea && !(vcpu->arch.shared->msr & MSR_PR) &&
(mp_ea >> SID_SHIFT) == esid;
}
#endif
static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
u64 *vsid) u64 *vsid)
{ {
@ -475,11 +575,13 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
struct kvmppc_slb *slb; struct kvmppc_slb *slb;
u64 gvsid = esid; u64 gvsid = esid;
ulong mp_ea = vcpu->arch.magic_page_ea; ulong mp_ea = vcpu->arch.magic_page_ea;
int pagesize = MMU_PAGE_64K;
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea); slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
if (slb) { if (slb) {
gvsid = slb->vsid; gvsid = slb->vsid;
pagesize = slb->base_page_size;
if (slb->tb) { if (slb->tb) {
gvsid <<= SID_SHIFT_1T - SID_SHIFT; gvsid <<= SID_SHIFT_1T - SID_SHIFT;
gvsid |= esid & ((1ul << (SID_SHIFT_1T - SID_SHIFT)) - 1); gvsid |= esid & ((1ul << (SID_SHIFT_1T - SID_SHIFT)) - 1);
@ -490,28 +592,41 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
case 0: case 0:
*vsid = VSID_REAL | esid; gvsid = VSID_REAL | esid;
break; break;
case MSR_IR: case MSR_IR:
*vsid = VSID_REAL_IR | gvsid; gvsid |= VSID_REAL_IR;
break; break;
case MSR_DR: case MSR_DR:
*vsid = VSID_REAL_DR | gvsid; gvsid |= VSID_REAL_DR;
break; break;
case MSR_DR|MSR_IR: case MSR_DR|MSR_IR:
if (!slb) if (!slb)
goto no_slb; goto no_slb;
*vsid = gvsid;
break; break;
default: default:
BUG(); BUG();
break; break;
} }
if (vcpu->arch.shared->msr & MSR_PR) #ifdef CONFIG_PPC_64K_PAGES
*vsid |= VSID_PR; /*
* Mark this as a 64k segment if the host is using
* 64k pages, the host MMU supports 64k pages and
* the guest segment page size is >= 64k,
* but not if this segment contains the magic page.
*/
if (pagesize >= MMU_PAGE_64K &&
mmu_psize_defs[MMU_PAGE_64K].shift &&
!segment_contains_magic_page(vcpu, esid))
gvsid |= VSID_64K;
#endif
if (vcpu->arch.shared->msr & MSR_PR)
gvsid |= VSID_PR;
*vsid = gvsid;
return 0; return 0;
no_slb: no_slb:

View file

@ -27,14 +27,14 @@
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include "trace.h" #include "trace_pr.h"
#define PTE_SIZE 12 #define PTE_SIZE 12
void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{ {
ppc_md.hpte_invalidate(pte->slot, pte->host_vpn, ppc_md.hpte_invalidate(pte->slot, pte->host_vpn,
MMU_PAGE_4K, MMU_PAGE_4K, MMU_SEGSIZE_256M, pte->pagesize, pte->pagesize, MMU_SEGSIZE_256M,
false); false);
} }
@ -78,7 +78,8 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
return NULL; return NULL;
} }
int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
bool iswrite)
{ {
unsigned long vpn; unsigned long vpn;
pfn_t hpaddr; pfn_t hpaddr;
@ -90,16 +91,26 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
int attempt = 0; int attempt = 0;
struct kvmppc_sid_map *map; struct kvmppc_sid_map *map;
int r = 0; int r = 0;
int hpsize = MMU_PAGE_4K;
bool writable;
unsigned long mmu_seq;
struct kvm *kvm = vcpu->kvm;
struct hpte_cache *cpte;
unsigned long gfn = orig_pte->raddr >> PAGE_SHIFT;
unsigned long pfn;
/* used to check for invalidations in progress */
mmu_seq = kvm->mmu_notifier_seq;
smp_rmb();
/* Get host physical address for gpa */ /* Get host physical address for gpa */
hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT); pfn = kvmppc_gfn_to_pfn(vcpu, gfn, iswrite, &writable);
if (is_error_noslot_pfn(hpaddr)) { if (is_error_noslot_pfn(pfn)) {
printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr); printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", gfn);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
hpaddr <<= PAGE_SHIFT; hpaddr = pfn << PAGE_SHIFT;
hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
/* and write the mapping ea -> hpa into the pt */ /* and write the mapping ea -> hpa into the pt */
vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
@ -117,20 +128,39 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
goto out; goto out;
} }
vsid = map->host_vsid; vpn = hpt_vpn(orig_pte->eaddr, map->host_vsid, MMU_SEGSIZE_256M);
vpn = hpt_vpn(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M);
if (!orig_pte->may_write) kvm_set_pfn_accessed(pfn);
rflags |= HPTE_R_PP; if (!orig_pte->may_write || !writable)
else rflags |= PP_RXRX;
mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); else {
mark_page_dirty(vcpu->kvm, gfn);
kvm_set_pfn_dirty(pfn);
}
if (!orig_pte->may_execute) if (!orig_pte->may_execute)
rflags |= HPTE_R_N; rflags |= HPTE_R_N;
else else
kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT); kvmppc_mmu_flush_icache(pfn);
hash = hpt_hash(vpn, PTE_SIZE, MMU_SEGSIZE_256M); /*
* Use 64K pages if possible; otherwise, on 64K page kernels,
* we need to transfer 4 more bits from guest real to host real addr.
*/
if (vsid & VSID_64K)
hpsize = MMU_PAGE_64K;
else
hpaddr |= orig_pte->raddr & (~0xfffULL & ~PAGE_MASK);
hash = hpt_hash(vpn, mmu_psize_defs[hpsize].shift, MMU_SEGSIZE_256M);
cpte = kvmppc_mmu_hpte_cache_next(vcpu);
spin_lock(&kvm->mmu_lock);
if (!cpte || mmu_notifier_retry(kvm, mmu_seq)) {
r = -EAGAIN;
goto out_unlock;
}
map_again: map_again:
hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
@ -139,11 +169,11 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
if (attempt > 1) if (attempt > 1)
if (ppc_md.hpte_remove(hpteg) < 0) { if (ppc_md.hpte_remove(hpteg) < 0) {
r = -1; r = -1;
goto out; goto out_unlock;
} }
ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags, ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags,
MMU_PAGE_4K, MMU_PAGE_4K, MMU_SEGSIZE_256M); hpsize, hpsize, MMU_SEGSIZE_256M);
if (ret < 0) { if (ret < 0) {
/* If we couldn't map a primary PTE, try a secondary */ /* If we couldn't map a primary PTE, try a secondary */
@ -152,8 +182,6 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
attempt++; attempt++;
goto map_again; goto map_again;
} else { } else {
struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
trace_kvm_book3s_64_mmu_map(rflags, hpteg, trace_kvm_book3s_64_mmu_map(rflags, hpteg,
vpn, hpaddr, orig_pte); vpn, hpaddr, orig_pte);
@ -164,19 +192,37 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
} }
pte->slot = hpteg + (ret & 7); cpte->slot = hpteg + (ret & 7);
pte->host_vpn = vpn; cpte->host_vpn = vpn;
pte->pte = *orig_pte; cpte->pte = *orig_pte;
pte->pfn = hpaddr >> PAGE_SHIFT; cpte->pfn = pfn;
cpte->pagesize = hpsize;
kvmppc_mmu_hpte_cache_map(vcpu, pte); kvmppc_mmu_hpte_cache_map(vcpu, cpte);
cpte = NULL;
} }
kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
out_unlock:
spin_unlock(&kvm->mmu_lock);
kvm_release_pfn_clean(pfn);
if (cpte)
kvmppc_mmu_hpte_cache_free(cpte);
out: out:
return r; return r;
} }
void kvmppc_mmu_unmap_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
{
u64 mask = 0xfffffffffULL;
u64 vsid;
vcpu->arch.mmu.esid_to_vsid(vcpu, pte->eaddr >> SID_SHIFT, &vsid);
if (vsid & VSID_64K)
mask = 0xffffffff0ULL;
kvmppc_mmu_pte_vflush(vcpu, pte->vpage, mask);
}
static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
{ {
struct kvmppc_sid_map *map; struct kvmppc_sid_map *map;
@ -291,6 +337,12 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
slb_vsid &= ~SLB_VSID_KP; slb_vsid &= ~SLB_VSID_KP;
slb_esid |= slb_index; slb_esid |= slb_index;
#ifdef CONFIG_PPC_64K_PAGES
/* Set host segment base page size to 64K if possible */
if (gvsid & VSID_64K)
slb_vsid |= mmu_psize_defs[MMU_PAGE_64K].sllp;
#endif
svcpu->slb[slb_index].esid = slb_esid; svcpu->slb[slb_index].esid = slb_esid;
svcpu->slb[slb_index].vsid = slb_vsid; svcpu->slb[slb_index].vsid = slb_vsid;
@ -326,7 +378,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
svcpu_put(svcpu); svcpu_put(svcpu);
} }
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy_pr(struct kvm_vcpu *vcpu)
{ {
kvmppc_mmu_hpte_destroy(vcpu); kvmppc_mmu_hpte_destroy(vcpu);
__destroy_context(to_book3s(vcpu)->context_id[0]); __destroy_context(to_book3s(vcpu)->context_id[0]);

View file

@ -260,10 +260,6 @@ int kvmppc_mmu_hv_init(void)
return 0; return 0;
} }
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
}
static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu) static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
{ {
kvmppc_set_msr(vcpu, MSR_SF | MSR_ME); kvmppc_set_msr(vcpu, MSR_SF | MSR_ME);
@ -451,7 +447,7 @@ static unsigned long kvmppc_mmu_get_real_addr(unsigned long v, unsigned long r,
} }
static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
struct kvmppc_pte *gpte, bool data) struct kvmppc_pte *gpte, bool data, bool iswrite)
{ {
struct kvm *kvm = vcpu->kvm; struct kvm *kvm = vcpu->kvm;
struct kvmppc_slb *slbe; struct kvmppc_slb *slbe;
@ -906,21 +902,22 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
return 0; return 0;
} }
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) int kvm_unmap_hva_hv(struct kvm *kvm, unsigned long hva)
{ {
if (kvm->arch.using_mmu_notifiers) if (kvm->arch.using_mmu_notifiers)
kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
return 0; return 0;
} }
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) int kvm_unmap_hva_range_hv(struct kvm *kvm, unsigned long start, unsigned long end)
{ {
if (kvm->arch.using_mmu_notifiers) if (kvm->arch.using_mmu_notifiers)
kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp); kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp);
return 0; return 0;
} }
void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot) void kvmppc_core_flush_memslot_hv(struct kvm *kvm,
struct kvm_memory_slot *memslot)
{ {
unsigned long *rmapp; unsigned long *rmapp;
unsigned long gfn; unsigned long gfn;
@ -994,7 +991,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
return ret; return ret;
} }
int kvm_age_hva(struct kvm *kvm, unsigned long hva) int kvm_age_hva_hv(struct kvm *kvm, unsigned long hva)
{ {
if (!kvm->arch.using_mmu_notifiers) if (!kvm->arch.using_mmu_notifiers)
return 0; return 0;
@ -1032,14 +1029,14 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
return ret; return ret;
} }
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) int kvm_test_age_hva_hv(struct kvm *kvm, unsigned long hva)
{ {
if (!kvm->arch.using_mmu_notifiers) if (!kvm->arch.using_mmu_notifiers)
return 0; return 0;
return kvm_handle_hva(kvm, hva, kvm_test_age_rmapp); return kvm_handle_hva(kvm, hva, kvm_test_age_rmapp);
} }
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte)
{ {
if (!kvm->arch.using_mmu_notifiers) if (!kvm->arch.using_mmu_notifiers)
return; return;
@ -1512,9 +1509,8 @@ static ssize_t kvm_htab_write(struct file *file, const char __user *buf,
kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T | kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
(VRMA_VSID << SLB_VSID_SHIFT_1T); (VRMA_VSID << SLB_VSID_SHIFT_1T);
lpcr = kvm->arch.lpcr & ~LPCR_VRMASD; lpcr = senc << (LPCR_VRMASD_SH - 4);
lpcr |= senc << (LPCR_VRMASD_SH - 4); kvmppc_update_lpcr(kvm, lpcr, LPCR_VRMASD);
kvm->arch.lpcr = lpcr;
rma_setup = 1; rma_setup = 1;
} }
++i; ++i;

View file

@ -74,3 +74,4 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
/* Didn't find the liobn, punt it to userspace */ /* Didn't find the liobn, punt it to userspace */
return H_TOO_HARD; return H_TOO_HARD;
} }
EXPORT_SYMBOL_GPL(kvmppc_h_put_tce);

View file

@ -86,8 +86,8 @@ static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level)
return true; return true;
} }
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, int kvmppc_core_emulate_op_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance) unsigned int inst, int *advance)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
int rt = get_rt(inst); int rt = get_rt(inst);
@ -172,7 +172,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
vcpu->arch.mmu.tlbie(vcpu, addr, large); vcpu->arch.mmu.tlbie(vcpu, addr, large);
break; break;
} }
#ifdef CONFIG_KVM_BOOK3S_64_PR #ifdef CONFIG_PPC_BOOK3S_64
case OP_31_XOP_FAKE_SC1: case OP_31_XOP_FAKE_SC1:
{ {
/* SC 1 papr hypercalls */ /* SC 1 papr hypercalls */
@ -267,12 +267,9 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
r = kvmppc_st(vcpu, &addr, 32, zeros, true); r = kvmppc_st(vcpu, &addr, 32, zeros, true);
if ((r == -ENOENT) || (r == -EPERM)) { if ((r == -ENOENT) || (r == -EPERM)) {
struct kvmppc_book3s_shadow_vcpu *svcpu;
svcpu = svcpu_get(vcpu);
*advance = 0; *advance = 0;
vcpu->arch.shared->dar = vaddr; vcpu->arch.shared->dar = vaddr;
svcpu->fault_dar = vaddr; vcpu->arch.fault_dar = vaddr;
dsisr = DSISR_ISSTORE; dsisr = DSISR_ISSTORE;
if (r == -ENOENT) if (r == -ENOENT)
@ -281,8 +278,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
dsisr |= DSISR_PROTFAULT; dsisr |= DSISR_PROTFAULT;
vcpu->arch.shared->dsisr = dsisr; vcpu->arch.shared->dsisr = dsisr;
svcpu->fault_dsisr = dsisr; vcpu->arch.fault_dsisr = dsisr;
svcpu_put(svcpu);
kvmppc_book3s_queue_irqprio(vcpu, kvmppc_book3s_queue_irqprio(vcpu,
BOOK3S_INTERRUPT_DATA_STORAGE); BOOK3S_INTERRUPT_DATA_STORAGE);
@ -349,7 +345,7 @@ static struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn)
return bat; return bat;
} }
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
@ -472,7 +468,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
return emulated; return emulated;
} }
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;

View file

@ -20,9 +20,10 @@
#include <linux/export.h> #include <linux/export.h>
#include <asm/kvm_book3s.h> #include <asm/kvm_book3s.h>
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline); EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline);
#else #endif
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline); EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline);
EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu); EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu);
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC

View file

@ -52,6 +52,9 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/module.h>
#include "book3s.h"
/* #define EXIT_DEBUG */ /* #define EXIT_DEBUG */
/* #define EXIT_DEBUG_SIMPLE */ /* #define EXIT_DEBUG_SIMPLE */
@ -66,7 +69,7 @@
static void kvmppc_end_cede(struct kvm_vcpu *vcpu); static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu); static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);
void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu) static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
{ {
int me; int me;
int cpu = vcpu->cpu; int cpu = vcpu->cpu;
@ -125,7 +128,7 @@ void kvmppc_fast_vcpu_kick(struct kvm_vcpu *vcpu)
* purely defensive; they should never fail.) * purely defensive; they should never fail.)
*/ */
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) static void kvmppc_core_vcpu_load_hv(struct kvm_vcpu *vcpu, int cpu)
{ {
struct kvmppc_vcore *vc = vcpu->arch.vcore; struct kvmppc_vcore *vc = vcpu->arch.vcore;
@ -143,7 +146,7 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
spin_unlock(&vcpu->arch.tbacct_lock); spin_unlock(&vcpu->arch.tbacct_lock);
} }
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_put_hv(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcore *vc = vcpu->arch.vcore; struct kvmppc_vcore *vc = vcpu->arch.vcore;
@ -155,17 +158,46 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
spin_unlock(&vcpu->arch.tbacct_lock); spin_unlock(&vcpu->arch.tbacct_lock);
} }
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) static void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr)
{ {
vcpu->arch.shregs.msr = msr; vcpu->arch.shregs.msr = msr;
kvmppc_end_cede(vcpu); kvmppc_end_cede(vcpu);
} }
void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr)
{ {
vcpu->arch.pvr = pvr; vcpu->arch.pvr = pvr;
} }
int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
{
unsigned long pcr = 0;
struct kvmppc_vcore *vc = vcpu->arch.vcore;
if (arch_compat) {
if (!cpu_has_feature(CPU_FTR_ARCH_206))
return -EINVAL; /* 970 has no compat mode support */
switch (arch_compat) {
case PVR_ARCH_205:
pcr = PCR_ARCH_205;
break;
case PVR_ARCH_206:
case PVR_ARCH_206p:
break;
default:
return -EINVAL;
}
}
spin_lock(&vc->lock);
vc->arch_compat = arch_compat;
vc->pcr = pcr;
spin_unlock(&vc->lock);
return 0;
}
void kvmppc_dump_regs(struct kvm_vcpu *vcpu) void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
{ {
int r; int r;
@ -195,7 +227,7 @@ void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
pr_err(" ESID = %.16llx VSID = %.16llx\n", pr_err(" ESID = %.16llx VSID = %.16llx\n",
vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv); vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv);
pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n", pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n",
vcpu->kvm->arch.lpcr, vcpu->kvm->arch.sdr1, vcpu->arch.vcore->lpcr, vcpu->kvm->arch.sdr1,
vcpu->arch.last_inst); vcpu->arch.last_inst);
} }
@ -489,7 +521,7 @@ static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu,
memset(dt, 0, sizeof(struct dtl_entry)); memset(dt, 0, sizeof(struct dtl_entry));
dt->dispatch_reason = 7; dt->dispatch_reason = 7;
dt->processor_id = vc->pcpu + vcpu->arch.ptid; dt->processor_id = vc->pcpu + vcpu->arch.ptid;
dt->timebase = now; dt->timebase = now + vc->tb_offset;
dt->enqueue_to_dispatch_time = stolen; dt->enqueue_to_dispatch_time = stolen;
dt->srr0 = kvmppc_get_pc(vcpu); dt->srr0 = kvmppc_get_pc(vcpu);
dt->srr1 = vcpu->arch.shregs.msr; dt->srr1 = vcpu->arch.shregs.msr;
@ -538,6 +570,15 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
} }
break; break;
case H_CONFER: case H_CONFER:
target = kvmppc_get_gpr(vcpu, 4);
if (target == -1)
break;
tvcpu = kvmppc_find_vcpu(vcpu->kvm, target);
if (!tvcpu) {
ret = H_PARAMETER;
break;
}
kvm_vcpu_yield_to(tvcpu);
break; break;
case H_REGISTER_VPA: case H_REGISTER_VPA:
ret = do_h_register_vpa(vcpu, kvmppc_get_gpr(vcpu, 4), ret = do_h_register_vpa(vcpu, kvmppc_get_gpr(vcpu, 4),
@ -576,8 +617,8 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
return RESUME_GUEST; return RESUME_GUEST;
} }
static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
struct task_struct *tsk) struct task_struct *tsk)
{ {
int r = RESUME_HOST; int r = RESUME_HOST;
@ -671,16 +712,16 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n",
vcpu->arch.trap, kvmppc_get_pc(vcpu), vcpu->arch.trap, kvmppc_get_pc(vcpu),
vcpu->arch.shregs.msr); vcpu->arch.shregs.msr);
run->hw.hardware_exit_reason = vcpu->arch.trap;
r = RESUME_HOST; r = RESUME_HOST;
BUG();
break; break;
} }
return r; return r;
} }
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, static int kvm_arch_vcpu_ioctl_get_sregs_hv(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs) struct kvm_sregs *sregs)
{ {
int i; int i;
@ -694,12 +735,12 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs) struct kvm_sregs *sregs)
{ {
int i, j; int i, j;
kvmppc_set_pvr(vcpu, sregs->pvr); kvmppc_set_pvr_hv(vcpu, sregs->pvr);
j = 0; j = 0;
for (i = 0; i < vcpu->arch.slb_nr; i++) { for (i = 0; i < vcpu->arch.slb_nr; i++) {
@ -714,7 +755,23 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr)
{
struct kvmppc_vcore *vc = vcpu->arch.vcore;
u64 mask;
spin_lock(&vc->lock);
/*
* Userspace can only modify DPFD (default prefetch depth),
* ILE (interrupt little-endian) and TC (translation control).
*/
mask = LPCR_DPFD | LPCR_ILE | LPCR_TC;
vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
spin_unlock(&vc->lock);
}
static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{ {
int r = 0; int r = 0;
long int i; long int i;
@ -749,6 +806,12 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
i = id - KVM_REG_PPC_PMC1; i = id - KVM_REG_PPC_PMC1;
*val = get_reg_val(id, vcpu->arch.pmc[i]); *val = get_reg_val(id, vcpu->arch.pmc[i]);
break; break;
case KVM_REG_PPC_SIAR:
*val = get_reg_val(id, vcpu->arch.siar);
break;
case KVM_REG_PPC_SDAR:
*val = get_reg_val(id, vcpu->arch.sdar);
break;
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
if (cpu_has_feature(CPU_FTR_VSX)) { if (cpu_has_feature(CPU_FTR_VSX)) {
@ -787,6 +850,18 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
val->vpaval.length = vcpu->arch.dtl.len; val->vpaval.length = vcpu->arch.dtl.len;
spin_unlock(&vcpu->arch.vpa_update_lock); spin_unlock(&vcpu->arch.vpa_update_lock);
break; break;
case KVM_REG_PPC_TB_OFFSET:
*val = get_reg_val(id, vcpu->arch.vcore->tb_offset);
break;
case KVM_REG_PPC_LPCR:
*val = get_reg_val(id, vcpu->arch.vcore->lpcr);
break;
case KVM_REG_PPC_PPR:
*val = get_reg_val(id, vcpu->arch.ppr);
break;
case KVM_REG_PPC_ARCH_COMPAT:
*val = get_reg_val(id, vcpu->arch.vcore->arch_compat);
break;
default: default:
r = -EINVAL; r = -EINVAL;
break; break;
@ -795,7 +870,8 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
return r; return r;
} }
int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{ {
int r = 0; int r = 0;
long int i; long int i;
@ -833,6 +909,12 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
i = id - KVM_REG_PPC_PMC1; i = id - KVM_REG_PPC_PMC1;
vcpu->arch.pmc[i] = set_reg_val(id, *val); vcpu->arch.pmc[i] = set_reg_val(id, *val);
break; break;
case KVM_REG_PPC_SIAR:
vcpu->arch.siar = set_reg_val(id, *val);
break;
case KVM_REG_PPC_SDAR:
vcpu->arch.sdar = set_reg_val(id, *val);
break;
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
if (cpu_has_feature(CPU_FTR_VSX)) { if (cpu_has_feature(CPU_FTR_VSX)) {
@ -880,6 +962,20 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
len -= len % sizeof(struct dtl_entry); len -= len % sizeof(struct dtl_entry);
r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len); r = set_vpa(vcpu, &vcpu->arch.dtl, addr, len);
break; break;
case KVM_REG_PPC_TB_OFFSET:
/* round up to multiple of 2^24 */
vcpu->arch.vcore->tb_offset =
ALIGN(set_reg_val(id, *val), 1UL << 24);
break;
case KVM_REG_PPC_LPCR:
kvmppc_set_lpcr(vcpu, set_reg_val(id, *val));
break;
case KVM_REG_PPC_PPR:
vcpu->arch.ppr = set_reg_val(id, *val);
break;
case KVM_REG_PPC_ARCH_COMPAT:
r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
break;
default: default:
r = -EINVAL; r = -EINVAL;
break; break;
@ -888,14 +984,8 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
return r; return r;
} }
int kvmppc_core_check_processor_compat(void) static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
{ unsigned int id)
if (cpu_has_feature(CPU_FTR_HVMODE))
return 0;
return -EIO;
}
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{ {
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
int err = -EINVAL; int err = -EINVAL;
@ -919,8 +1009,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
vcpu->arch.mmcr[0] = MMCR0_FC; vcpu->arch.mmcr[0] = MMCR0_FC;
vcpu->arch.ctrl = CTRL_RUNLATCH; vcpu->arch.ctrl = CTRL_RUNLATCH;
/* default to host PVR, since we can't spoof it */ /* default to host PVR, since we can't spoof it */
vcpu->arch.pvr = mfspr(SPRN_PVR); kvmppc_set_pvr_hv(vcpu, mfspr(SPRN_PVR));
kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
spin_lock_init(&vcpu->arch.vpa_update_lock); spin_lock_init(&vcpu->arch.vpa_update_lock);
spin_lock_init(&vcpu->arch.tbacct_lock); spin_lock_init(&vcpu->arch.tbacct_lock);
vcpu->arch.busy_preempt = TB_NIL; vcpu->arch.busy_preempt = TB_NIL;
@ -940,6 +1029,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
spin_lock_init(&vcore->lock); spin_lock_init(&vcore->lock);
init_waitqueue_head(&vcore->wq); init_waitqueue_head(&vcore->wq);
vcore->preempt_tb = TB_NIL; vcore->preempt_tb = TB_NIL;
vcore->lpcr = kvm->arch.lpcr;
} }
kvm->arch.vcores[core] = vcore; kvm->arch.vcores[core] = vcore;
kvm->arch.online_vcores++; kvm->arch.online_vcores++;
@ -972,7 +1062,7 @@ static void unpin_vpa(struct kvm *kvm, struct kvmppc_vpa *vpa)
vpa->dirty); vpa->dirty);
} }
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_free_hv(struct kvm_vcpu *vcpu)
{ {
spin_lock(&vcpu->arch.vpa_update_lock); spin_lock(&vcpu->arch.vpa_update_lock);
unpin_vpa(vcpu->kvm, &vcpu->arch.dtl); unpin_vpa(vcpu->kvm, &vcpu->arch.dtl);
@ -983,6 +1073,12 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu); kmem_cache_free(kvm_vcpu_cache, vcpu);
} }
static int kvmppc_core_check_requests_hv(struct kvm_vcpu *vcpu)
{
/* Indicate we want to get back into the guest */
return 1;
}
static void kvmppc_set_timer(struct kvm_vcpu *vcpu) static void kvmppc_set_timer(struct kvm_vcpu *vcpu)
{ {
unsigned long dec_nsec, now; unsigned long dec_nsec, now;
@ -1264,8 +1360,8 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
ret = RESUME_GUEST; ret = RESUME_GUEST;
if (vcpu->arch.trap) if (vcpu->arch.trap)
ret = kvmppc_handle_exit(vcpu->arch.kvm_run, vcpu, ret = kvmppc_handle_exit_hv(vcpu->arch.kvm_run, vcpu,
vcpu->arch.run_task); vcpu->arch.run_task);
vcpu->arch.ret = ret; vcpu->arch.ret = ret;
vcpu->arch.trap = 0; vcpu->arch.trap = 0;
@ -1424,7 +1520,7 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
return vcpu->arch.ret; return vcpu->arch.ret;
} }
int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu) static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
{ {
int r; int r;
int srcu_idx; int srcu_idx;
@ -1546,7 +1642,8 @@ static const struct file_operations kvm_rma_fops = {
.release = kvm_rma_release, .release = kvm_rma_release,
}; };
long kvm_vm_ioctl_allocate_rma(struct kvm *kvm, struct kvm_allocate_rma *ret) static long kvm_vm_ioctl_allocate_rma(struct kvm *kvm,
struct kvm_allocate_rma *ret)
{ {
long fd; long fd;
struct kvm_rma_info *ri; struct kvm_rma_info *ri;
@ -1592,7 +1689,8 @@ static void kvmppc_add_seg_page_size(struct kvm_ppc_one_seg_page_size **sps,
(*sps)++; (*sps)++;
} }
int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info) static int kvm_vm_ioctl_get_smmu_info_hv(struct kvm *kvm,
struct kvm_ppc_smmu_info *info)
{ {
struct kvm_ppc_one_seg_page_size *sps; struct kvm_ppc_one_seg_page_size *sps;
@ -1613,7 +1711,8 @@ int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
/* /*
* Get (and clear) the dirty memory log for a memory slot. * Get (and clear) the dirty memory log for a memory slot.
*/ */
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) static int kvm_vm_ioctl_get_dirty_log_hv(struct kvm *kvm,
struct kvm_dirty_log *log)
{ {
struct kvm_memory_slot *memslot; struct kvm_memory_slot *memslot;
int r; int r;
@ -1667,8 +1766,8 @@ static void unpin_slot(struct kvm_memory_slot *memslot)
} }
} }
void kvmppc_core_free_memslot(struct kvm_memory_slot *free, static void kvmppc_core_free_memslot_hv(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
if (!dont || free->arch.rmap != dont->arch.rmap) { if (!dont || free->arch.rmap != dont->arch.rmap) {
vfree(free->arch.rmap); vfree(free->arch.rmap);
@ -1681,8 +1780,8 @@ void kvmppc_core_free_memslot(struct kvm_memory_slot *free,
} }
} }
int kvmppc_core_create_memslot(struct kvm_memory_slot *slot, static int kvmppc_core_create_memslot_hv(struct kvm_memory_slot *slot,
unsigned long npages) unsigned long npages)
{ {
slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap)); slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
if (!slot->arch.rmap) if (!slot->arch.rmap)
@ -1692,9 +1791,9 @@ int kvmppc_core_create_memslot(struct kvm_memory_slot *slot,
return 0; return 0;
} }
int kvmppc_core_prepare_memory_region(struct kvm *kvm, static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
struct kvm_memory_slot *memslot, struct kvm_memory_slot *memslot,
struct kvm_userspace_memory_region *mem) struct kvm_userspace_memory_region *mem)
{ {
unsigned long *phys; unsigned long *phys;
@ -1710,9 +1809,9 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm,
return 0; return 0;
} }
void kvmppc_core_commit_memory_region(struct kvm *kvm, static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
struct kvm_userspace_memory_region *mem, struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old) const struct kvm_memory_slot *old)
{ {
unsigned long npages = mem->memory_size >> PAGE_SHIFT; unsigned long npages = mem->memory_size >> PAGE_SHIFT;
struct kvm_memory_slot *memslot; struct kvm_memory_slot *memslot;
@ -1729,6 +1828,37 @@ void kvmppc_core_commit_memory_region(struct kvm *kvm,
} }
} }
/*
* Update LPCR values in kvm->arch and in vcores.
* Caller must hold kvm->lock.
*/
void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr, unsigned long mask)
{
long int i;
u32 cores_done = 0;
if ((kvm->arch.lpcr & mask) == lpcr)
return;
kvm->arch.lpcr = (kvm->arch.lpcr & ~mask) | lpcr;
for (i = 0; i < KVM_MAX_VCORES; ++i) {
struct kvmppc_vcore *vc = kvm->arch.vcores[i];
if (!vc)
continue;
spin_lock(&vc->lock);
vc->lpcr = (vc->lpcr & ~mask) | lpcr;
spin_unlock(&vc->lock);
if (++cores_done >= kvm->arch.online_vcores)
break;
}
}
static void kvmppc_mmu_destroy_hv(struct kvm_vcpu *vcpu)
{
return;
}
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu) static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
{ {
int err = 0; int err = 0;
@ -1737,7 +1867,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
unsigned long hva; unsigned long hva;
struct kvm_memory_slot *memslot; struct kvm_memory_slot *memslot;
struct vm_area_struct *vma; struct vm_area_struct *vma;
unsigned long lpcr, senc; unsigned long lpcr = 0, senc;
unsigned long lpcr_mask = 0;
unsigned long psize, porder; unsigned long psize, porder;
unsigned long rma_size; unsigned long rma_size;
unsigned long rmls; unsigned long rmls;
@ -1802,9 +1933,9 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
senc = slb_pgsize_encoding(psize); senc = slb_pgsize_encoding(psize);
kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T | kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
(VRMA_VSID << SLB_VSID_SHIFT_1T); (VRMA_VSID << SLB_VSID_SHIFT_1T);
lpcr = kvm->arch.lpcr & ~LPCR_VRMASD; lpcr_mask = LPCR_VRMASD;
lpcr |= senc << (LPCR_VRMASD_SH - 4); /* the -4 is to account for senc values starting at 0x10 */
kvm->arch.lpcr = lpcr; lpcr = senc << (LPCR_VRMASD_SH - 4);
/* Create HPTEs in the hash page table for the VRMA */ /* Create HPTEs in the hash page table for the VRMA */
kvmppc_map_vrma(vcpu, memslot, porder); kvmppc_map_vrma(vcpu, memslot, porder);
@ -1825,23 +1956,21 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
kvm->arch.rma = ri; kvm->arch.rma = ri;
/* Update LPCR and RMOR */ /* Update LPCR and RMOR */
lpcr = kvm->arch.lpcr;
if (cpu_has_feature(CPU_FTR_ARCH_201)) { if (cpu_has_feature(CPU_FTR_ARCH_201)) {
/* PPC970; insert RMLS value (split field) in HID4 */ /* PPC970; insert RMLS value (split field) in HID4 */
lpcr &= ~((1ul << HID4_RMLS0_SH) | lpcr_mask = (1ul << HID4_RMLS0_SH) |
(3ul << HID4_RMLS2_SH)); (3ul << HID4_RMLS2_SH) | HID4_RMOR;
lpcr |= ((rmls >> 2) << HID4_RMLS0_SH) | lpcr = ((rmls >> 2) << HID4_RMLS0_SH) |
((rmls & 3) << HID4_RMLS2_SH); ((rmls & 3) << HID4_RMLS2_SH);
/* RMOR is also in HID4 */ /* RMOR is also in HID4 */
lpcr |= ((ri->base_pfn >> (26 - PAGE_SHIFT)) & 0xffff) lpcr |= ((ri->base_pfn >> (26 - PAGE_SHIFT)) & 0xffff)
<< HID4_RMOR_SH; << HID4_RMOR_SH;
} else { } else {
/* POWER7 */ /* POWER7 */
lpcr &= ~(LPCR_VPM0 | LPCR_VRMA_L); lpcr_mask = LPCR_VPM0 | LPCR_VRMA_L | LPCR_RMLS;
lpcr |= rmls << LPCR_RMLS_SH; lpcr = rmls << LPCR_RMLS_SH;
kvm->arch.rmor = ri->base_pfn << PAGE_SHIFT; kvm->arch.rmor = ri->base_pfn << PAGE_SHIFT;
} }
kvm->arch.lpcr = lpcr;
pr_info("KVM: Using RMO at %lx size %lx (LPCR = %lx)\n", pr_info("KVM: Using RMO at %lx size %lx (LPCR = %lx)\n",
ri->base_pfn << PAGE_SHIFT, rma_size, lpcr); ri->base_pfn << PAGE_SHIFT, rma_size, lpcr);
@ -1860,6 +1989,8 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
} }
} }
kvmppc_update_lpcr(kvm, lpcr, lpcr_mask);
/* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */ /* Order updates to kvm->arch.lpcr etc. vs. rma_setup_done */
smp_wmb(); smp_wmb();
kvm->arch.rma_setup_done = 1; kvm->arch.rma_setup_done = 1;
@ -1875,7 +2006,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
goto out_srcu; goto out_srcu;
} }
int kvmppc_core_init_vm(struct kvm *kvm) static int kvmppc_core_init_vm_hv(struct kvm *kvm)
{ {
unsigned long lpcr, lpid; unsigned long lpcr, lpid;
@ -1893,9 +2024,6 @@ int kvmppc_core_init_vm(struct kvm *kvm)
*/ */
cpumask_setall(&kvm->arch.need_tlb_flush); cpumask_setall(&kvm->arch.need_tlb_flush);
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
INIT_LIST_HEAD(&kvm->arch.rtas_tokens);
kvm->arch.rma = NULL; kvm->arch.rma = NULL;
kvm->arch.host_sdr1 = mfspr(SPRN_SDR1); kvm->arch.host_sdr1 = mfspr(SPRN_SDR1);
@ -1931,61 +2059,162 @@ int kvmppc_core_init_vm(struct kvm *kvm)
return 0; return 0;
} }
void kvmppc_core_destroy_vm(struct kvm *kvm) static void kvmppc_free_vcores(struct kvm *kvm)
{
long int i;
for (i = 0; i < KVM_MAX_VCORES; ++i)
kfree(kvm->arch.vcores[i]);
kvm->arch.online_vcores = 0;
}
static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
{ {
uninhibit_secondary_onlining(); uninhibit_secondary_onlining();
kvmppc_free_vcores(kvm);
if (kvm->arch.rma) { if (kvm->arch.rma) {
kvm_release_rma(kvm->arch.rma); kvm_release_rma(kvm->arch.rma);
kvm->arch.rma = NULL; kvm->arch.rma = NULL;
} }
kvmppc_rtas_tokens_free(kvm);
kvmppc_free_hpt(kvm); kvmppc_free_hpt(kvm);
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
}
/* These are stubs for now */
void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
{
} }
/* We don't need to emulate any privileged instructions or dcbz */ /* We don't need to emulate any privileged instructions or dcbz */
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, static int kvmppc_core_emulate_op_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance) unsigned int inst, int *advance)
{ {
return EMULATE_FAIL; return EMULATE_FAIL;
} }
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) static int kvmppc_core_emulate_mtspr_hv(struct kvm_vcpu *vcpu, int sprn,
ulong spr_val)
{ {
return EMULATE_FAIL; return EMULATE_FAIL;
} }
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) static int kvmppc_core_emulate_mfspr_hv(struct kvm_vcpu *vcpu, int sprn,
ulong *spr_val)
{ {
return EMULATE_FAIL; return EMULATE_FAIL;
} }
static int kvmppc_book3s_hv_init(void) static int kvmppc_core_check_processor_compat_hv(void)
{ {
int r; if (!cpu_has_feature(CPU_FTR_HVMODE))
return -EIO;
return 0;
}
r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); static long kvm_arch_vm_ioctl_hv(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm *kvm __maybe_unused = filp->private_data;
void __user *argp = (void __user *)arg;
long r;
if (r) switch (ioctl) {
return r;
r = kvmppc_mmu_hv_init(); case KVM_ALLOCATE_RMA: {
struct kvm_allocate_rma rma;
struct kvm *kvm = filp->private_data;
r = kvm_vm_ioctl_allocate_rma(kvm, &rma);
if (r >= 0 && copy_to_user(argp, &rma, sizeof(rma)))
r = -EFAULT;
break;
}
case KVM_PPC_ALLOCATE_HTAB: {
u32 htab_order;
r = -EFAULT;
if (get_user(htab_order, (u32 __user *)argp))
break;
r = kvmppc_alloc_reset_hpt(kvm, &htab_order);
if (r)
break;
r = -EFAULT;
if (put_user(htab_order, (u32 __user *)argp))
break;
r = 0;
break;
}
case KVM_PPC_GET_HTAB_FD: {
struct kvm_get_htab_fd ghf;
r = -EFAULT;
if (copy_from_user(&ghf, argp, sizeof(ghf)))
break;
r = kvm_vm_ioctl_get_htab_fd(kvm, &ghf);
break;
}
default:
r = -ENOTTY;
}
return r; return r;
} }
static void kvmppc_book3s_hv_exit(void) static struct kvmppc_ops kvm_ops_hv = {
.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
.get_one_reg = kvmppc_get_one_reg_hv,
.set_one_reg = kvmppc_set_one_reg_hv,
.vcpu_load = kvmppc_core_vcpu_load_hv,
.vcpu_put = kvmppc_core_vcpu_put_hv,
.set_msr = kvmppc_set_msr_hv,
.vcpu_run = kvmppc_vcpu_run_hv,
.vcpu_create = kvmppc_core_vcpu_create_hv,
.vcpu_free = kvmppc_core_vcpu_free_hv,
.check_requests = kvmppc_core_check_requests_hv,
.get_dirty_log = kvm_vm_ioctl_get_dirty_log_hv,
.flush_memslot = kvmppc_core_flush_memslot_hv,
.prepare_memory_region = kvmppc_core_prepare_memory_region_hv,
.commit_memory_region = kvmppc_core_commit_memory_region_hv,
.unmap_hva = kvm_unmap_hva_hv,
.unmap_hva_range = kvm_unmap_hva_range_hv,
.age_hva = kvm_age_hva_hv,
.test_age_hva = kvm_test_age_hva_hv,
.set_spte_hva = kvm_set_spte_hva_hv,
.mmu_destroy = kvmppc_mmu_destroy_hv,
.free_memslot = kvmppc_core_free_memslot_hv,
.create_memslot = kvmppc_core_create_memslot_hv,
.init_vm = kvmppc_core_init_vm_hv,
.destroy_vm = kvmppc_core_destroy_vm_hv,
.get_smmu_info = kvm_vm_ioctl_get_smmu_info_hv,
.emulate_op = kvmppc_core_emulate_op_hv,
.emulate_mtspr = kvmppc_core_emulate_mtspr_hv,
.emulate_mfspr = kvmppc_core_emulate_mfspr_hv,
.fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv,
.arch_vm_ioctl = kvm_arch_vm_ioctl_hv,
};
static int kvmppc_book3s_init_hv(void)
{ {
kvm_exit(); int r;
/*
* FIXME!! Do we need to check on all cpus ?
*/
r = kvmppc_core_check_processor_compat_hv();
if (r < 0)
return r;
kvm_ops_hv.owner = THIS_MODULE;
kvmppc_hv_ops = &kvm_ops_hv;
r = kvmppc_mmu_hv_init();
return r;
} }
module_init(kvmppc_book3s_hv_init); static void kvmppc_book3s_exit_hv(void)
module_exit(kvmppc_book3s_hv_exit); {
kvmppc_hv_ops = NULL;
}
module_init(kvmppc_book3s_init_hv);
module_exit(kvmppc_book3s_exit_hv);
MODULE_LICENSE("GPL");

View file

@ -158,9 +158,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
* Interrupts are enabled again at this point. * Interrupts are enabled again at this point.
*/ */
.global kvmppc_handler_highmem
kvmppc_handler_highmem:
/* /*
* Register usage at this point: * Register usage at this point:
* *

View file

@ -33,30 +33,6 @@
#error Need to fix lppaca and SLB shadow accesses in little endian mode #error Need to fix lppaca and SLB shadow accesses in little endian mode
#endif #endif
/*****************************************************************************
* *
* Real Mode handlers that need to be in the linear mapping *
* *
****************************************************************************/
.globl kvmppc_skip_interrupt
kvmppc_skip_interrupt:
mfspr r13,SPRN_SRR0
addi r13,r13,4
mtspr SPRN_SRR0,r13
GET_SCRATCH0(r13)
rfid
b .
.globl kvmppc_skip_Hinterrupt
kvmppc_skip_Hinterrupt:
mfspr r13,SPRN_HSRR0
addi r13,r13,4
mtspr SPRN_HSRR0,r13
GET_SCRATCH0(r13)
hrfid
b .
/* /*
* Call kvmppc_hv_entry in real mode. * Call kvmppc_hv_entry in real mode.
* Must be called with interrupts hard-disabled. * Must be called with interrupts hard-disabled.
@ -66,8 +42,11 @@ kvmppc_skip_Hinterrupt:
* LR = return address to continue at after eventually re-enabling MMU * LR = return address to continue at after eventually re-enabling MMU
*/ */
_GLOBAL(kvmppc_hv_entry_trampoline) _GLOBAL(kvmppc_hv_entry_trampoline)
mflr r0
std r0, PPC_LR_STKOFF(r1)
stdu r1, -112(r1)
mfmsr r10 mfmsr r10
LOAD_REG_ADDR(r5, kvmppc_hv_entry) LOAD_REG_ADDR(r5, kvmppc_call_hv_entry)
li r0,MSR_RI li r0,MSR_RI
andc r0,r10,r0 andc r0,r10,r0
li r6,MSR_IR | MSR_DR li r6,MSR_IR | MSR_DR
@ -77,11 +56,103 @@ _GLOBAL(kvmppc_hv_entry_trampoline)
mtsrr1 r6 mtsrr1 r6
RFI RFI
/****************************************************************************** kvmppc_call_hv_entry:
* * bl kvmppc_hv_entry
* Entry code *
* * /* Back from guest - restore host state and return to caller */
*****************************************************************************/
/* Restore host DABR and DABRX */
ld r5,HSTATE_DABR(r13)
li r6,7
mtspr SPRN_DABR,r5
mtspr SPRN_DABRX,r6
/* Restore SPRG3 */
ld r3,PACA_SPRG3(r13)
mtspr SPRN_SPRG3,r3
/*
* Reload DEC. HDEC interrupts were disabled when
* we reloaded the host's LPCR value.
*/
ld r3, HSTATE_DECEXP(r13)
mftb r4
subf r4, r4, r3
mtspr SPRN_DEC, r4
/* Reload the host's PMU registers */
ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */
lbz r4, LPPACA_PMCINUSE(r3)
cmpwi r4, 0
beq 23f /* skip if not */
lwz r3, HSTATE_PMC(r13)
lwz r4, HSTATE_PMC + 4(r13)
lwz r5, HSTATE_PMC + 8(r13)
lwz r6, HSTATE_PMC + 12(r13)
lwz r8, HSTATE_PMC + 16(r13)
lwz r9, HSTATE_PMC + 20(r13)
BEGIN_FTR_SECTION
lwz r10, HSTATE_PMC + 24(r13)
lwz r11, HSTATE_PMC + 28(r13)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
mtspr SPRN_PMC1, r3
mtspr SPRN_PMC2, r4
mtspr SPRN_PMC3, r5
mtspr SPRN_PMC4, r6
mtspr SPRN_PMC5, r8
mtspr SPRN_PMC6, r9
BEGIN_FTR_SECTION
mtspr SPRN_PMC7, r10
mtspr SPRN_PMC8, r11
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
ld r3, HSTATE_MMCR(r13)
ld r4, HSTATE_MMCR + 8(r13)
ld r5, HSTATE_MMCR + 16(r13)
mtspr SPRN_MMCR1, r4
mtspr SPRN_MMCRA, r5
mtspr SPRN_MMCR0, r3
isync
23:
/*
* For external and machine check interrupts, we need
* to call the Linux handler to process the interrupt.
* We do that by jumping to absolute address 0x500 for
* external interrupts, or the machine_check_fwnmi label
* for machine checks (since firmware might have patched
* the vector area at 0x200). The [h]rfid at the end of the
* handler will return to the book3s_hv_interrupts.S code.
* For other interrupts we do the rfid to get back
* to the book3s_hv_interrupts.S code here.
*/
ld r8, 112+PPC_LR_STKOFF(r1)
addi r1, r1, 112
ld r7, HSTATE_HOST_MSR(r13)
cmpwi cr1, r12, BOOK3S_INTERRUPT_MACHINE_CHECK
cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
BEGIN_FTR_SECTION
beq 11f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* RFI into the highmem handler, or branch to interrupt handler */
mfmsr r6
li r0, MSR_RI
andc r6, r6, r0
mtmsrd r6, 1 /* Clear RI in MSR */
mtsrr0 r8
mtsrr1 r7
beqa 0x500 /* external interrupt (PPC970) */
beq cr1, 13f /* machine check */
RFI
/* On POWER7, we have external interrupts set to use HSRR0/1 */
11: mtspr SPRN_HSRR0, r8
mtspr SPRN_HSRR1, r7
ba 0x500
13: b machine_check_fwnmi
/* /*
* We come in here when wakened from nap mode on a secondary hw thread. * We come in here when wakened from nap mode on a secondary hw thread.
@ -137,7 +208,7 @@ kvm_start_guest:
cmpdi r4,0 cmpdi r4,0
/* if we have no vcpu to run, go back to sleep */ /* if we have no vcpu to run, go back to sleep */
beq kvm_no_guest beq kvm_no_guest
b kvmppc_hv_entry b 30f
27: /* XXX should handle hypervisor maintenance interrupts etc. here */ 27: /* XXX should handle hypervisor maintenance interrupts etc. here */
b kvm_no_guest b kvm_no_guest
@ -147,6 +218,57 @@ kvm_start_guest:
stw r8,HSTATE_SAVED_XIRR(r13) stw r8,HSTATE_SAVED_XIRR(r13)
b kvm_no_guest b kvm_no_guest
30: bl kvmppc_hv_entry
/* Back from the guest, go back to nap */
/* Clear our vcpu pointer so we don't come back in early */
li r0, 0
std r0, HSTATE_KVM_VCPU(r13)
lwsync
/* Clear any pending IPI - we're an offline thread */
ld r5, HSTATE_XICS_PHYS(r13)
li r7, XICS_XIRR
lwzcix r3, r5, r7 /* ack any pending interrupt */
rlwinm. r0, r3, 0, 0xffffff /* any pending? */
beq 37f
sync
li r0, 0xff
li r6, XICS_MFRR
stbcix r0, r5, r6 /* clear the IPI */
stwcix r3, r5, r7 /* EOI it */
37: sync
/* increment the nap count and then go to nap mode */
ld r4, HSTATE_KVM_VCORE(r13)
addi r4, r4, VCORE_NAP_COUNT
lwsync /* make previous updates visible */
51: lwarx r3, 0, r4
addi r3, r3, 1
stwcx. r3, 0, r4
bne 51b
kvm_no_guest:
li r0, KVM_HWTHREAD_IN_NAP
stb r0, HSTATE_HWTHREAD_STATE(r13)
li r3, LPCR_PECE0
mfspr r4, SPRN_LPCR
rlwimi r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
mtspr SPRN_LPCR, r4
isync
std r0, HSTATE_SCRATCH0(r13)
ptesync
ld r0, HSTATE_SCRATCH0(r13)
1: cmpd r0, r0
bne 1b
nap
b .
/******************************************************************************
* *
* Entry code *
* *
*****************************************************************************/
.global kvmppc_hv_entry .global kvmppc_hv_entry
kvmppc_hv_entry: kvmppc_hv_entry:
@ -159,7 +281,8 @@ kvmppc_hv_entry:
* all other volatile GPRS = free * all other volatile GPRS = free
*/ */
mflr r0 mflr r0
std r0, HSTATE_VMHANDLER(r13) std r0, PPC_LR_STKOFF(r1)
stdu r1, -112(r1)
/* Set partition DABR */ /* Set partition DABR */
/* Do this before re-enabling PMU to avoid P7 DABR corruption bug */ /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
@ -200,8 +323,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
ld r3, VCPU_MMCR(r4) ld r3, VCPU_MMCR(r4)
ld r5, VCPU_MMCR + 8(r4) ld r5, VCPU_MMCR + 8(r4)
ld r6, VCPU_MMCR + 16(r4) ld r6, VCPU_MMCR + 16(r4)
ld r7, VCPU_SIAR(r4)
ld r8, VCPU_SDAR(r4)
mtspr SPRN_MMCR1, r5 mtspr SPRN_MMCR1, r5
mtspr SPRN_MMCRA, r6 mtspr SPRN_MMCRA, r6
mtspr SPRN_SIAR, r7
mtspr SPRN_SDAR, r8
mtspr SPRN_MMCR0, r3 mtspr SPRN_MMCR0, r3
isync isync
@ -254,22 +381,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* Save R1 in the PACA */ /* Save R1 in the PACA */
std r1, HSTATE_HOST_R1(r13) std r1, HSTATE_HOST_R1(r13)
/* Increment yield count if they have a VPA */
ld r3, VCPU_VPA(r4)
cmpdi r3, 0
beq 25f
lwz r5, LPPACA_YIELDCOUNT(r3)
addi r5, r5, 1
stw r5, LPPACA_YIELDCOUNT(r3)
li r6, 1
stb r6, VCPU_VPA_DIRTY(r4)
25:
/* Load up DAR and DSISR */ /* Load up DAR and DSISR */
ld r5, VCPU_DAR(r4) ld r5, VCPU_DAR(r4)
lwz r6, VCPU_DSISR(r4) lwz r6, VCPU_DSISR(r4)
mtspr SPRN_DAR, r5 mtspr SPRN_DAR, r5
mtspr SPRN_DSISR, r6 mtspr SPRN_DSISR, r6
li r6, KVM_GUEST_MODE_HOST_HV
stb r6, HSTATE_IN_GUEST(r13)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
/* Restore AMR and UAMOR, set AMOR to all 1s */ /* Restore AMR and UAMOR, set AMOR to all 1s */
ld r5,VCPU_AMR(r4) ld r5,VCPU_AMR(r4)
@ -343,7 +463,28 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
bdnz 28b bdnz 28b
ptesync ptesync
22: li r0,1 /* Add timebase offset onto timebase */
22: ld r8,VCORE_TB_OFFSET(r5)
cmpdi r8,0
beq 37f
mftb r6 /* current host timebase */
add r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
mftb r7 /* check if lower 24 bits overflowed */
clrldi r6,r6,40
clrldi r7,r7,40
cmpld r7,r6
bge 37f
addis r8,r8,0x100 /* if so, increment upper 40 bits */
mtspr SPRN_TBU40,r8
/* Load guest PCR value to select appropriate compat mode */
37: ld r7, VCORE_PCR(r5)
cmpdi r7, 0
beq 38f
mtspr SPRN_PCR, r7
38:
li r0,1
stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */ stb r0,VCORE_IN_GUEST(r5) /* signal secondaries to continue */
b 10f b 10f
@ -353,12 +494,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
beq 20b beq 20b
/* Set LPCR and RMOR. */ /* Set LPCR and RMOR. */
10: ld r8,KVM_LPCR(r9) 10: ld r8,VCORE_LPCR(r5)
mtspr SPRN_LPCR,r8 mtspr SPRN_LPCR,r8
ld r8,KVM_RMOR(r9) ld r8,KVM_RMOR(r9)
mtspr SPRN_RMOR,r8 mtspr SPRN_RMOR,r8
isync isync
/* Increment yield count if they have a VPA */
ld r3, VCPU_VPA(r4)
cmpdi r3, 0
beq 25f
lwz r5, LPPACA_YIELDCOUNT(r3)
addi r5, r5, 1
stw r5, LPPACA_YIELDCOUNT(r3)
li r6, 1
stb r6, VCPU_VPA_DIRTY(r4)
25:
/* Check if HDEC expires soon */ /* Check if HDEC expires soon */
mfspr r3,SPRN_HDEC mfspr r3,SPRN_HDEC
cmpwi r3,10 cmpwi r3,10
@ -405,7 +556,8 @@ toc_tlbie_lock:
bne 24b bne 24b
isync isync
ld r7,KVM_LPCR(r9) /* use kvm->arch.lpcr to store HID4 */ ld r5,HSTATE_KVM_VCORE(r13)
ld r7,VCORE_LPCR(r5) /* use vcore->lpcr to store HID4 */
li r0,0x18f li r0,0x18f
rotldi r0,r0,HID4_LPID5_SH /* all lpid bits in HID4 = 1 */ rotldi r0,r0,HID4_LPID5_SH /* all lpid bits in HID4 = 1 */
or r0,r7,r0 or r0,r7,r0
@ -541,7 +693,7 @@ fast_guest_return:
mtspr SPRN_HSRR1,r11 mtspr SPRN_HSRR1,r11
/* Activate guest mode, so faults get handled by KVM */ /* Activate guest mode, so faults get handled by KVM */
li r9, KVM_GUEST_MODE_GUEST li r9, KVM_GUEST_MODE_GUEST_HV
stb r9, HSTATE_IN_GUEST(r13) stb r9, HSTATE_IN_GUEST(r13)
/* Enter guest */ /* Enter guest */
@ -550,13 +702,15 @@ BEGIN_FTR_SECTION
ld r5, VCPU_CFAR(r4) ld r5, VCPU_CFAR(r4)
mtspr SPRN_CFAR, r5 mtspr SPRN_CFAR, r5
END_FTR_SECTION_IFSET(CPU_FTR_CFAR) END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
BEGIN_FTR_SECTION
ld r0, VCPU_PPR(r4)
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ld r5, VCPU_LR(r4) ld r5, VCPU_LR(r4)
lwz r6, VCPU_CR(r4) lwz r6, VCPU_CR(r4)
mtlr r5 mtlr r5
mtcr r6 mtcr r6
ld r0, VCPU_GPR(R0)(r4)
ld r1, VCPU_GPR(R1)(r4) ld r1, VCPU_GPR(R1)(r4)
ld r2, VCPU_GPR(R2)(r4) ld r2, VCPU_GPR(R2)(r4)
ld r3, VCPU_GPR(R3)(r4) ld r3, VCPU_GPR(R3)(r4)
@ -570,6 +724,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
ld r12, VCPU_GPR(R12)(r4) ld r12, VCPU_GPR(R12)(r4)
ld r13, VCPU_GPR(R13)(r4) ld r13, VCPU_GPR(R13)(r4)
BEGIN_FTR_SECTION
mtspr SPRN_PPR, r0
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ld r0, VCPU_GPR(R0)(r4)
ld r4, VCPU_GPR(R4)(r4) ld r4, VCPU_GPR(R4)(r4)
hrfid hrfid
@ -584,8 +742,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
/* /*
* We come here from the first-level interrupt handlers. * We come here from the first-level interrupt handlers.
*/ */
.globl kvmppc_interrupt .globl kvmppc_interrupt_hv
kvmppc_interrupt: kvmppc_interrupt_hv:
/* /*
* Register contents: * Register contents:
* R12 = interrupt vector * R12 = interrupt vector
@ -595,6 +753,19 @@ kvmppc_interrupt:
*/ */
/* abuse host_r2 as third scratch area; we get r2 from PACATOC(r13) */ /* abuse host_r2 as third scratch area; we get r2 from PACATOC(r13) */
std r9, HSTATE_HOST_R2(r13) std r9, HSTATE_HOST_R2(r13)
lbz r9, HSTATE_IN_GUEST(r13)
cmpwi r9, KVM_GUEST_MODE_HOST_HV
beq kvmppc_bad_host_intr
#ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
cmpwi r9, KVM_GUEST_MODE_GUEST
ld r9, HSTATE_HOST_R2(r13)
beq kvmppc_interrupt_pr
#endif
/* We're now back in the host but in guest MMU context */
li r9, KVM_GUEST_MODE_HOST_HV
stb r9, HSTATE_IN_GUEST(r13)
ld r9, HSTATE_KVM_VCPU(r13) ld r9, HSTATE_KVM_VCPU(r13)
/* Save registers */ /* Save registers */
@ -620,6 +791,10 @@ BEGIN_FTR_SECTION
ld r3, HSTATE_CFAR(r13) ld r3, HSTATE_CFAR(r13)
std r3, VCPU_CFAR(r9) std r3, VCPU_CFAR(r9)
END_FTR_SECTION_IFSET(CPU_FTR_CFAR) END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
BEGIN_FTR_SECTION
ld r4, HSTATE_PPR(r13)
std r4, VCPU_PPR(r9)
END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
/* Restore R1/R2 so we can handle faults */ /* Restore R1/R2 so we can handle faults */
ld r1, HSTATE_HOST_R1(r13) ld r1, HSTATE_HOST_R1(r13)
@ -642,10 +817,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
std r3, VCPU_GPR(R13)(r9) std r3, VCPU_GPR(R13)(r9)
std r4, VCPU_LR(r9) std r4, VCPU_LR(r9)
/* Unset guest mode */
li r0, KVM_GUEST_MODE_NONE
stb r0, HSTATE_IN_GUEST(r13)
stw r12,VCPU_TRAP(r9) stw r12,VCPU_TRAP(r9)
/* Save HEIR (HV emulation assist reg) in last_inst /* Save HEIR (HV emulation assist reg) in last_inst
@ -696,46 +867,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
* set, we know the host wants us out so let's do it now * set, we know the host wants us out so let's do it now
*/ */
do_ext_interrupt: do_ext_interrupt:
lbz r0, HSTATE_HOST_IPI(r13) bl kvmppc_read_intr
cmpwi r0, 0 cmpdi r3, 0
bne ext_interrupt_to_host bgt ext_interrupt_to_host
/* Now read the interrupt from the ICP */
ld r5, HSTATE_XICS_PHYS(r13)
li r7, XICS_XIRR
cmpdi r5, 0
beq- ext_interrupt_to_host
lwzcix r3, r5, r7
rlwinm. r0, r3, 0, 0xffffff
sync
beq 3f /* if nothing pending in the ICP */
/* We found something in the ICP...
*
* If it's not an IPI, stash it in the PACA and return to
* the host, we don't (yet) handle directing real external
* interrupts directly to the guest
*/
cmpwi r0, XICS_IPI
bne ext_stash_for_host
/* It's an IPI, clear the MFRR and EOI it */
li r0, 0xff
li r6, XICS_MFRR
stbcix r0, r5, r6 /* clear the IPI */
stwcix r3, r5, r7 /* EOI it */
sync
/* We need to re-check host IPI now in case it got set in the
* meantime. If it's clear, we bounce the interrupt to the
* guest
*/
lbz r0, HSTATE_HOST_IPI(r13)
cmpwi r0, 0
bne- 1f
/* Allright, looks like an IPI for the guest, we need to set MER */ /* Allright, looks like an IPI for the guest, we need to set MER */
3:
/* Check if any CPU is heading out to the host, if so head out too */ /* Check if any CPU is heading out to the host, if so head out too */
ld r5, HSTATE_KVM_VCORE(r13) ld r5, HSTATE_KVM_VCORE(r13)
lwz r0, VCORE_ENTRY_EXIT(r5) lwz r0, VCORE_ENTRY_EXIT(r5)
@ -764,27 +900,9 @@ do_ext_interrupt:
mtspr SPRN_LPCR, r8 mtspr SPRN_LPCR, r8
b fast_guest_return b fast_guest_return
/* We raced with the host, we need to resend that IPI, bummer */
1: li r0, IPI_PRIORITY
stbcix r0, r5, r6 /* set the IPI */
sync
b ext_interrupt_to_host
ext_stash_for_host:
/* It's not an IPI and it's for the host, stash it in the PACA
* before exit, it will be picked up by the host ICP driver
*/
stw r3, HSTATE_SAVED_XIRR(r13)
ext_interrupt_to_host: ext_interrupt_to_host:
guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */
/* Save DEC */
mfspr r5,SPRN_DEC
mftb r6
extsw r5,r5
add r5,r5,r6
std r5,VCPU_DEC_EXPIRES(r9)
/* Save more register state */ /* Save more register state */
mfdar r6 mfdar r6
mfdsisr r7 mfdsisr r7
@ -954,7 +1072,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
mtspr SPRN_SDR1,r6 /* switch to partition page table */ mtspr SPRN_SDR1,r6 /* switch to partition page table */
mtspr SPRN_LPID,r7 mtspr SPRN_LPID,r7
isync isync
li r0,0
/* Subtract timebase offset from timebase */
ld r8,VCORE_TB_OFFSET(r5)
cmpdi r8,0
beq 17f
mftb r6 /* current host timebase */
subf r8,r8,r6
mtspr SPRN_TBU40,r8 /* update upper 40 bits */
mftb r7 /* check if lower 24 bits overflowed */
clrldi r6,r6,40
clrldi r7,r7,40
cmpld r7,r6
bge 17f
addis r8,r8,0x100 /* if so, increment upper 40 bits */
mtspr SPRN_TBU40,r8
/* Reset PCR */
17: ld r0, VCORE_PCR(r5)
cmpdi r0, 0
beq 18f
li r0, 0
mtspr SPRN_PCR, r0
18:
/* Signal secondary CPUs to continue */
stb r0,VCORE_IN_GUEST(r5) stb r0,VCORE_IN_GUEST(r5)
lis r8,0x7fff /* MAX_INT@h */ lis r8,0x7fff /* MAX_INT@h */
mtspr SPRN_HDEC,r8 mtspr SPRN_HDEC,r8
@ -1052,6 +1193,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
1: addi r8,r8,16 1: addi r8,r8,16
.endr .endr
/* Save DEC */
mfspr r5,SPRN_DEC
mftb r6
extsw r5,r5
add r5,r5,r6
std r5,VCPU_DEC_EXPIRES(r9)
/* Save and reset AMR and UAMOR before turning on the MMU */ /* Save and reset AMR and UAMOR before turning on the MMU */
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mfspr r5,SPRN_AMR mfspr r5,SPRN_AMR
@ -1062,6 +1210,10 @@ BEGIN_FTR_SECTION
mtspr SPRN_AMR,r6 mtspr SPRN_AMR,r6
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* Unset guest mode */
li r0, KVM_GUEST_MODE_NONE
stb r0, HSTATE_IN_GUEST(r13)
/* Switch DSCR back to host value */ /* Switch DSCR back to host value */
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mfspr r8, SPRN_DSCR mfspr r8, SPRN_DSCR
@ -1134,9 +1286,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */
b 22f b 22f
21: mfspr r5, SPRN_MMCR1 21: mfspr r5, SPRN_MMCR1
mfspr r7, SPRN_SIAR
mfspr r8, SPRN_SDAR
std r4, VCPU_MMCR(r9) std r4, VCPU_MMCR(r9)
std r5, VCPU_MMCR + 8(r9) std r5, VCPU_MMCR + 8(r9)
std r6, VCPU_MMCR + 16(r9) std r6, VCPU_MMCR + 16(r9)
std r7, VCPU_SIAR(r9)
std r8, VCPU_SDAR(r9)
mfspr r3, SPRN_PMC1 mfspr r3, SPRN_PMC1
mfspr r4, SPRN_PMC2 mfspr r4, SPRN_PMC2
mfspr r5, SPRN_PMC3 mfspr r5, SPRN_PMC3
@ -1158,103 +1314,30 @@ BEGIN_FTR_SECTION
stw r11, VCPU_PMC + 28(r9) stw r11, VCPU_PMC + 28(r9)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
22: 22:
ld r0, 112+PPC_LR_STKOFF(r1)
addi r1, r1, 112
mtlr r0
blr
secondary_too_late:
ld r5,HSTATE_KVM_VCORE(r13)
HMT_LOW
13: lbz r3,VCORE_IN_GUEST(r5)
cmpwi r3,0
bne 13b
HMT_MEDIUM
li r0, KVM_GUEST_MODE_NONE
stb r0, HSTATE_IN_GUEST(r13)
ld r11,PACA_SLBSHADOWPTR(r13)
/* Secondary threads go off to take a nap on POWER7 */ .rept SLB_NUM_BOLTED
BEGIN_FTR_SECTION ld r5,SLBSHADOW_SAVEAREA(r11)
lwz r0,VCPU_PTID(r9) ld r6,SLBSHADOW_SAVEAREA+8(r11)
cmpwi r0,0 andis. r7,r5,SLB_ESID_V@h
bne secondary_nap beq 1f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) slbmte r6,r5
1: addi r11,r11,16
/* Restore host DABR and DABRX */ .endr
ld r5,HSTATE_DABR(r13) b 22b
li r6,7
mtspr SPRN_DABR,r5
mtspr SPRN_DABRX,r6
/* Restore SPRG3 */
ld r3,PACA_SPRG3(r13)
mtspr SPRN_SPRG3,r3
/*
* Reload DEC. HDEC interrupts were disabled when
* we reloaded the host's LPCR value.
*/
ld r3, HSTATE_DECEXP(r13)
mftb r4
subf r4, r4, r3
mtspr SPRN_DEC, r4
/* Reload the host's PMU registers */
ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */
lbz r4, LPPACA_PMCINUSE(r3)
cmpwi r4, 0
beq 23f /* skip if not */
lwz r3, HSTATE_PMC(r13)
lwz r4, HSTATE_PMC + 4(r13)
lwz r5, HSTATE_PMC + 8(r13)
lwz r6, HSTATE_PMC + 12(r13)
lwz r8, HSTATE_PMC + 16(r13)
lwz r9, HSTATE_PMC + 20(r13)
BEGIN_FTR_SECTION
lwz r10, HSTATE_PMC + 24(r13)
lwz r11, HSTATE_PMC + 28(r13)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
mtspr SPRN_PMC1, r3
mtspr SPRN_PMC2, r4
mtspr SPRN_PMC3, r5
mtspr SPRN_PMC4, r6
mtspr SPRN_PMC5, r8
mtspr SPRN_PMC6, r9
BEGIN_FTR_SECTION
mtspr SPRN_PMC7, r10
mtspr SPRN_PMC8, r11
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
ld r3, HSTATE_MMCR(r13)
ld r4, HSTATE_MMCR + 8(r13)
ld r5, HSTATE_MMCR + 16(r13)
mtspr SPRN_MMCR1, r4
mtspr SPRN_MMCRA, r5
mtspr SPRN_MMCR0, r3
isync
23:
/*
* For external and machine check interrupts, we need
* to call the Linux handler to process the interrupt.
* We do that by jumping to absolute address 0x500 for
* external interrupts, or the machine_check_fwnmi label
* for machine checks (since firmware might have patched
* the vector area at 0x200). The [h]rfid at the end of the
* handler will return to the book3s_hv_interrupts.S code.
* For other interrupts we do the rfid to get back
* to the book3s_hv_interrupts.S code here.
*/
ld r8, HSTATE_VMHANDLER(r13)
ld r7, HSTATE_HOST_MSR(r13)
cmpwi cr1, r12, BOOK3S_INTERRUPT_MACHINE_CHECK
cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
BEGIN_FTR_SECTION
beq 11f
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* RFI into the highmem handler, or branch to interrupt handler */
mfmsr r6
li r0, MSR_RI
andc r6, r6, r0
mtmsrd r6, 1 /* Clear RI in MSR */
mtsrr0 r8
mtsrr1 r7
beqa 0x500 /* external interrupt (PPC970) */
beq cr1, 13f /* machine check */
RFI
/* On POWER7, we have external interrupts set to use HSRR0/1 */
11: mtspr SPRN_HSRR0, r8
mtspr SPRN_HSRR1, r7
ba 0x500
13: b machine_check_fwnmi
/* /*
* Check whether an HDSI is an HPTE not found fault or something else. * Check whether an HDSI is an HPTE not found fault or something else.
@ -1333,7 +1416,7 @@ fast_interrupt_c_return:
stw r8, VCPU_LAST_INST(r9) stw r8, VCPU_LAST_INST(r9)
/* Unset guest mode. */ /* Unset guest mode. */
li r0, KVM_GUEST_MODE_NONE li r0, KVM_GUEST_MODE_HOST_HV
stb r0, HSTATE_IN_GUEST(r13) stb r0, HSTATE_IN_GUEST(r13)
b guest_exit_cont b guest_exit_cont
@ -1701,67 +1784,70 @@ machine_check_realmode:
rotldi r11, r11, 63 rotldi r11, r11, 63
b fast_interrupt_c_return b fast_interrupt_c_return
secondary_too_late: /*
ld r5,HSTATE_KVM_VCORE(r13) * Determine what sort of external interrupt is pending (if any).
HMT_LOW * Returns:
13: lbz r3,VCORE_IN_GUEST(r5) * 0 if no interrupt is pending
cmpwi r3,0 * 1 if an interrupt is pending that needs to be handled by the host
bne 13b * -1 if there was a guest wakeup IPI (which has now been cleared)
HMT_MEDIUM */
ld r11,PACA_SLBSHADOWPTR(r13) kvmppc_read_intr:
/* see if a host IPI is pending */
li r3, 1
lbz r0, HSTATE_HOST_IPI(r13)
cmpwi r0, 0
bne 1f
.rept SLB_NUM_BOLTED /* Now read the interrupt from the ICP */
ld r5,SLBSHADOW_SAVEAREA(r11) ld r6, HSTATE_XICS_PHYS(r13)
ld r6,SLBSHADOW_SAVEAREA+8(r11)
andis. r7,r5,SLB_ESID_V@h
beq 1f
slbmte r6,r5
1: addi r11,r11,16
.endr
secondary_nap:
/* Clear our vcpu pointer so we don't come back in early */
li r0, 0
std r0, HSTATE_KVM_VCPU(r13)
lwsync
/* Clear any pending IPI - assume we're a secondary thread */
ld r5, HSTATE_XICS_PHYS(r13)
li r7, XICS_XIRR li r7, XICS_XIRR
lwzcix r3, r5, r7 /* ack any pending interrupt */ cmpdi r6, 0
rlwinm. r0, r3, 0, 0xffffff /* any pending? */ beq- 1f
beq 37f lwzcix r0, r6, r7
rlwinm. r3, r0, 0, 0xffffff
sync sync
li r0, 0xff beq 1f /* if nothing pending in the ICP */
li r6, XICS_MFRR
stbcix r0, r5, r6 /* clear the IPI */
stwcix r3, r5, r7 /* EOI it */
37: sync
/* increment the nap count and then go to nap mode */ /* We found something in the ICP...
ld r4, HSTATE_KVM_VCORE(r13) *
addi r4, r4, VCORE_NAP_COUNT * If it's not an IPI, stash it in the PACA and return to
lwsync /* make previous updates visible */ * the host, we don't (yet) handle directing real external
51: lwarx r3, 0, r4 * interrupts directly to the guest
addi r3, r3, 1 */
stwcx. r3, 0, r4 cmpwi r3, XICS_IPI /* if there is, is it an IPI? */
bne 51b li r3, 1
bne 42f
kvm_no_guest: /* It's an IPI, clear the MFRR and EOI it */
li r0, KVM_HWTHREAD_IN_NAP li r3, 0xff
stb r0, HSTATE_HWTHREAD_STATE(r13) li r8, XICS_MFRR
stbcix r3, r6, r8 /* clear the IPI */
stwcix r0, r6, r7 /* EOI it */
sync
li r3, LPCR_PECE0 /* We need to re-check host IPI now in case it got set in the
mfspr r4, SPRN_LPCR * meantime. If it's clear, we bounce the interrupt to the
rlwimi r4, r3, 0, LPCR_PECE0 | LPCR_PECE1 * guest
mtspr SPRN_LPCR, r4 */
isync lbz r0, HSTATE_HOST_IPI(r13)
std r0, HSTATE_SCRATCH0(r13) cmpwi r0, 0
ptesync bne- 43f
ld r0, HSTATE_SCRATCH0(r13)
1: cmpd r0, r0 /* OK, it's an IPI for us */
bne 1b li r3, -1
nap 1: blr
b .
42: /* It's not an IPI and it's for the host, stash it in the PACA
* before exit, it will be picked up by the host ICP driver
*/
stw r0, HSTATE_SAVED_XIRR(r13)
b 1b
43: /* We raced with the host, we need to resend that IPI, bummer */
li r0, IPI_PRIORITY
stbcix r0, r6, r8 /* set the IPI */
sync
b 1b
/* /*
* Save away FP, VMX and VSX registers. * Save away FP, VMX and VSX registers.
@ -1879,3 +1965,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
lwz r7,VCPU_VRSAVE(r4) lwz r7,VCPU_VRSAVE(r4)
mtspr SPRN_VRSAVE,r7 mtspr SPRN_VRSAVE,r7
blr blr
/*
* We come here if we get any exception or interrupt while we are
* executing host real mode code while in guest MMU context.
* For now just spin, but we should do something better.
*/
kvmppc_bad_host_intr:
b .

View file

@ -26,8 +26,12 @@
#if defined(CONFIG_PPC_BOOK3S_64) #if defined(CONFIG_PPC_BOOK3S_64)
#define FUNC(name) GLUE(.,name) #define FUNC(name) GLUE(.,name)
#define GET_SHADOW_VCPU(reg) addi reg, r13, PACA_SVCPU
#elif defined(CONFIG_PPC_BOOK3S_32) #elif defined(CONFIG_PPC_BOOK3S_32)
#define FUNC(name) name #define FUNC(name) name
#define GET_SHADOW_VCPU(reg) lwz reg, (THREAD + THREAD_KVM_SVCPU)(r2)
#endif /* CONFIG_PPC_BOOK3S_XX */ #endif /* CONFIG_PPC_BOOK3S_XX */
#define VCPU_LOAD_NVGPRS(vcpu) \ #define VCPU_LOAD_NVGPRS(vcpu) \
@ -87,8 +91,14 @@ kvm_start_entry:
VCPU_LOAD_NVGPRS(r4) VCPU_LOAD_NVGPRS(r4)
kvm_start_lightweight: kvm_start_lightweight:
/* Copy registers into shadow vcpu so we can access them in real mode */
GET_SHADOW_VCPU(r3)
bl FUNC(kvmppc_copy_to_svcpu)
nop
REST_GPR(4, r1)
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
/* Get the dcbz32 flag */
PPC_LL r3, VCPU_HFLAGS(r4) PPC_LL r3, VCPU_HFLAGS(r4)
rldicl r3, r3, 0, 63 /* r3 &= 1 */ rldicl r3, r3, 0, 63 /* r3 &= 1 */
stb r3, HSTATE_RESTORE_HID5(r13) stb r3, HSTATE_RESTORE_HID5(r13)
@ -111,9 +121,6 @@ kvm_start_lightweight:
* *
*/ */
.global kvmppc_handler_highmem
kvmppc_handler_highmem:
/* /*
* Register usage at this point: * Register usage at this point:
* *
@ -125,18 +132,31 @@ kvmppc_handler_highmem:
* *
*/ */
/* R7 = vcpu */ /* Transfer reg values from shadow vcpu back to vcpu struct */
PPC_LL r7, GPR4(r1) /* On 64-bit, interrupts are still off at this point */
PPC_LL r3, GPR4(r1) /* vcpu pointer */
GET_SHADOW_VCPU(r4)
bl FUNC(kvmppc_copy_from_svcpu)
nop
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
/* Re-enable interrupts */
ld r3, HSTATE_HOST_MSR(r13)
ori r3, r3, MSR_EE
MTMSR_EERI(r3)
/* /*
* Reload kernel SPRG3 value. * Reload kernel SPRG3 value.
* No need to save guest value as usermode can't modify SPRG3. * No need to save guest value as usermode can't modify SPRG3.
*/ */
ld r3, PACA_SPRG3(r13) ld r3, PACA_SPRG3(r13)
mtspr SPRN_SPRG3, r3 mtspr SPRN_SPRG3, r3
#endif /* CONFIG_PPC_BOOK3S_64 */ #endif /* CONFIG_PPC_BOOK3S_64 */
/* R7 = vcpu */
PPC_LL r7, GPR4(r1)
PPC_STL r14, VCPU_GPR(R14)(r7) PPC_STL r14, VCPU_GPR(R14)(r7)
PPC_STL r15, VCPU_GPR(R15)(r7) PPC_STL r15, VCPU_GPR(R15)(r7)
PPC_STL r16, VCPU_GPR(R16)(r7) PPC_STL r16, VCPU_GPR(R16)(r7)
@ -161,7 +181,7 @@ kvmppc_handler_highmem:
/* Restore r3 (kvm_run) and r4 (vcpu) */ /* Restore r3 (kvm_run) and r4 (vcpu) */
REST_2GPRS(3, r1) REST_2GPRS(3, r1)
bl FUNC(kvmppc_handle_exit) bl FUNC(kvmppc_handle_exit_pr)
/* If RESUME_GUEST, get back in the loop */ /* If RESUME_GUEST, get back in the loop */
cmpwi r3, RESUME_GUEST cmpwi r3, RESUME_GUEST

View file

@ -28,7 +28,7 @@
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include "trace.h" #include "trace_pr.h"
#define PTE_SIZE 12 #define PTE_SIZE 12
@ -56,6 +56,14 @@ static inline u64 kvmppc_mmu_hash_vpte_long(u64 vpage)
HPTEG_HASH_BITS_VPTE_LONG); HPTEG_HASH_BITS_VPTE_LONG);
} }
#ifdef CONFIG_PPC_BOOK3S_64
static inline u64 kvmppc_mmu_hash_vpte_64k(u64 vpage)
{
return hash_64((vpage & 0xffffffff0ULL) >> 4,
HPTEG_HASH_BITS_VPTE_64K);
}
#endif
void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte) void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{ {
u64 index; u64 index;
@ -83,6 +91,15 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
hlist_add_head_rcu(&pte->list_vpte_long, hlist_add_head_rcu(&pte->list_vpte_long,
&vcpu3s->hpte_hash_vpte_long[index]); &vcpu3s->hpte_hash_vpte_long[index]);
#ifdef CONFIG_PPC_BOOK3S_64
/* Add to vPTE_64k list */
index = kvmppc_mmu_hash_vpte_64k(pte->pte.vpage);
hlist_add_head_rcu(&pte->list_vpte_64k,
&vcpu3s->hpte_hash_vpte_64k[index]);
#endif
vcpu3s->hpte_cache_count++;
spin_unlock(&vcpu3s->mmu_lock); spin_unlock(&vcpu3s->mmu_lock);
} }
@ -113,10 +130,13 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
hlist_del_init_rcu(&pte->list_pte_long); hlist_del_init_rcu(&pte->list_pte_long);
hlist_del_init_rcu(&pte->list_vpte); hlist_del_init_rcu(&pte->list_vpte);
hlist_del_init_rcu(&pte->list_vpte_long); hlist_del_init_rcu(&pte->list_vpte_long);
#ifdef CONFIG_PPC_BOOK3S_64
hlist_del_init_rcu(&pte->list_vpte_64k);
#endif
vcpu3s->hpte_cache_count--;
spin_unlock(&vcpu3s->mmu_lock); spin_unlock(&vcpu3s->mmu_lock);
vcpu3s->hpte_cache_count--;
call_rcu(&pte->rcu_head, free_pte_rcu); call_rcu(&pte->rcu_head, free_pte_rcu);
} }
@ -219,6 +239,29 @@ static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
rcu_read_unlock(); rcu_read_unlock();
} }
#ifdef CONFIG_PPC_BOOK3S_64
/* Flush with mask 0xffffffff0 */
static void kvmppc_mmu_pte_vflush_64k(struct kvm_vcpu *vcpu, u64 guest_vp)
{
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hlist_head *list;
struct hpte_cache *pte;
u64 vp_mask = 0xffffffff0ULL;
list = &vcpu3s->hpte_hash_vpte_64k[
kvmppc_mmu_hash_vpte_64k(guest_vp)];
rcu_read_lock();
/* Check the list for matching entries and invalidate */
hlist_for_each_entry_rcu(pte, list, list_vpte_64k)
if ((pte->pte.vpage & vp_mask) == guest_vp)
invalidate_pte(vcpu, pte);
rcu_read_unlock();
}
#endif
/* Flush with mask 0xffffff000 */ /* Flush with mask 0xffffff000 */
static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp) static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
{ {
@ -249,6 +292,11 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
case 0xfffffffffULL: case 0xfffffffffULL:
kvmppc_mmu_pte_vflush_short(vcpu, guest_vp); kvmppc_mmu_pte_vflush_short(vcpu, guest_vp);
break; break;
#ifdef CONFIG_PPC_BOOK3S_64
case 0xffffffff0ULL:
kvmppc_mmu_pte_vflush_64k(vcpu, guest_vp);
break;
#endif
case 0xffffff000ULL: case 0xffffff000ULL:
kvmppc_mmu_pte_vflush_long(vcpu, guest_vp); kvmppc_mmu_pte_vflush_long(vcpu, guest_vp);
break; break;
@ -285,15 +333,19 @@ struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
struct hpte_cache *pte; struct hpte_cache *pte;
pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
vcpu3s->hpte_cache_count++;
if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM) if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM)
kvmppc_mmu_pte_flush_all(vcpu); kvmppc_mmu_pte_flush_all(vcpu);
pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
return pte; return pte;
} }
void kvmppc_mmu_hpte_cache_free(struct hpte_cache *pte)
{
kmem_cache_free(hpte_cache, pte);
}
void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu) void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu)
{ {
kvmppc_mmu_pte_flush(vcpu, 0, 0); kvmppc_mmu_pte_flush(vcpu, 0, 0);
@ -320,6 +372,10 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
ARRAY_SIZE(vcpu3s->hpte_hash_vpte)); ARRAY_SIZE(vcpu3s->hpte_hash_vpte));
kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_long, kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_long,
ARRAY_SIZE(vcpu3s->hpte_hash_vpte_long)); ARRAY_SIZE(vcpu3s->hpte_hash_vpte_long));
#ifdef CONFIG_PPC_BOOK3S_64
kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_64k,
ARRAY_SIZE(vcpu3s->hpte_hash_vpte_64k));
#endif
spin_lock_init(&vcpu3s->mmu_lock); spin_lock_init(&vcpu3s->mmu_lock);

View file

@ -40,8 +40,12 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/module.h>
#include "trace.h" #include "book3s.h"
#define CREATE_TRACE_POINTS
#include "trace_pr.h"
/* #define EXIT_DEBUG */ /* #define EXIT_DEBUG */
/* #define DEBUG_EXT */ /* #define DEBUG_EXT */
@ -56,29 +60,25 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
#define HW_PAGE_SIZE PAGE_SIZE #define HW_PAGE_SIZE PAGE_SIZE
#endif #endif
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)
{ {
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb)); memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb));
memcpy(&get_paca()->shadow_vcpu, to_book3s(vcpu)->shadow_vcpu,
sizeof(get_paca()->shadow_vcpu));
svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max; svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
svcpu_put(svcpu); svcpu_put(svcpu);
#endif #endif
vcpu->cpu = smp_processor_id(); vcpu->cpu = smp_processor_id();
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
current->thread.kvm_shadow_vcpu = to_book3s(vcpu)->shadow_vcpu; current->thread.kvm_shadow_vcpu = vcpu->arch.shadow_vcpu;
#endif #endif
} }
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
{ {
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb)); memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
memcpy(to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
sizeof(get_paca()->shadow_vcpu));
to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max; to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
svcpu_put(svcpu); svcpu_put(svcpu);
#endif #endif
@ -87,7 +87,61 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
vcpu->cpu = -1; vcpu->cpu = -1;
} }
int kvmppc_core_check_requests(struct kvm_vcpu *vcpu) /* Copy data needed by real-mode code from vcpu to shadow vcpu */
void kvmppc_copy_to_svcpu(struct kvmppc_book3s_shadow_vcpu *svcpu,
struct kvm_vcpu *vcpu)
{
svcpu->gpr[0] = vcpu->arch.gpr[0];
svcpu->gpr[1] = vcpu->arch.gpr[1];
svcpu->gpr[2] = vcpu->arch.gpr[2];
svcpu->gpr[3] = vcpu->arch.gpr[3];
svcpu->gpr[4] = vcpu->arch.gpr[4];
svcpu->gpr[5] = vcpu->arch.gpr[5];
svcpu->gpr[6] = vcpu->arch.gpr[6];
svcpu->gpr[7] = vcpu->arch.gpr[7];
svcpu->gpr[8] = vcpu->arch.gpr[8];
svcpu->gpr[9] = vcpu->arch.gpr[9];
svcpu->gpr[10] = vcpu->arch.gpr[10];
svcpu->gpr[11] = vcpu->arch.gpr[11];
svcpu->gpr[12] = vcpu->arch.gpr[12];
svcpu->gpr[13] = vcpu->arch.gpr[13];
svcpu->cr = vcpu->arch.cr;
svcpu->xer = vcpu->arch.xer;
svcpu->ctr = vcpu->arch.ctr;
svcpu->lr = vcpu->arch.lr;
svcpu->pc = vcpu->arch.pc;
}
/* Copy data touched by real-mode code from shadow vcpu back to vcpu */
void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
struct kvmppc_book3s_shadow_vcpu *svcpu)
{
vcpu->arch.gpr[0] = svcpu->gpr[0];
vcpu->arch.gpr[1] = svcpu->gpr[1];
vcpu->arch.gpr[2] = svcpu->gpr[2];
vcpu->arch.gpr[3] = svcpu->gpr[3];
vcpu->arch.gpr[4] = svcpu->gpr[4];
vcpu->arch.gpr[5] = svcpu->gpr[5];
vcpu->arch.gpr[6] = svcpu->gpr[6];
vcpu->arch.gpr[7] = svcpu->gpr[7];
vcpu->arch.gpr[8] = svcpu->gpr[8];
vcpu->arch.gpr[9] = svcpu->gpr[9];
vcpu->arch.gpr[10] = svcpu->gpr[10];
vcpu->arch.gpr[11] = svcpu->gpr[11];
vcpu->arch.gpr[12] = svcpu->gpr[12];
vcpu->arch.gpr[13] = svcpu->gpr[13];
vcpu->arch.cr = svcpu->cr;
vcpu->arch.xer = svcpu->xer;
vcpu->arch.ctr = svcpu->ctr;
vcpu->arch.lr = svcpu->lr;
vcpu->arch.pc = svcpu->pc;
vcpu->arch.shadow_srr1 = svcpu->shadow_srr1;
vcpu->arch.fault_dar = svcpu->fault_dar;
vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
vcpu->arch.last_inst = svcpu->last_inst;
}
static int kvmppc_core_check_requests_pr(struct kvm_vcpu *vcpu)
{ {
int r = 1; /* Indicate we want to get back into the guest */ int r = 1; /* Indicate we want to get back into the guest */
@ -100,44 +154,69 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
} }
/************* MMU Notifiers *************/ /************* MMU Notifiers *************/
static void do_kvm_unmap_hva(struct kvm *kvm, unsigned long start,
unsigned long end)
{
long i;
struct kvm_vcpu *vcpu;
struct kvm_memslots *slots;
struct kvm_memory_slot *memslot;
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) slots = kvm_memslots(kvm);
kvm_for_each_memslot(memslot, slots) {
unsigned long hva_start, hva_end;
gfn_t gfn, gfn_end;
hva_start = max(start, memslot->userspace_addr);
hva_end = min(end, memslot->userspace_addr +
(memslot->npages << PAGE_SHIFT));
if (hva_start >= hva_end)
continue;
/*
* {gfn(page) | page intersects with [hva_start, hva_end)} =
* {gfn, gfn+1, ..., gfn_end-1}.
*/
gfn = hva_to_gfn_memslot(hva_start, memslot);
gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
kvm_for_each_vcpu(i, vcpu, kvm)
kvmppc_mmu_pte_pflush(vcpu, gfn << PAGE_SHIFT,
gfn_end << PAGE_SHIFT);
}
}
static int kvm_unmap_hva_pr(struct kvm *kvm, unsigned long hva)
{ {
trace_kvm_unmap_hva(hva); trace_kvm_unmap_hva(hva);
/* do_kvm_unmap_hva(kvm, hva, hva + PAGE_SIZE);
* Flush all shadow tlb entries everywhere. This is slow, but
* we are 100% sure that we catch the to be unmapped page
*/
kvm_flush_remote_tlbs(kvm);
return 0; return 0;
} }
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end) static int kvm_unmap_hva_range_pr(struct kvm *kvm, unsigned long start,
unsigned long end)
{ {
/* kvm_unmap_hva flushes everything anyways */ do_kvm_unmap_hva(kvm, start, end);
kvm_unmap_hva(kvm, start);
return 0; return 0;
} }
int kvm_age_hva(struct kvm *kvm, unsigned long hva) static int kvm_age_hva_pr(struct kvm *kvm, unsigned long hva)
{ {
/* XXX could be more clever ;) */ /* XXX could be more clever ;) */
return 0; return 0;
} }
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) static int kvm_test_age_hva_pr(struct kvm *kvm, unsigned long hva)
{ {
/* XXX could be more clever ;) */ /* XXX could be more clever ;) */
return 0; return 0;
} }
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) static void kvm_set_spte_hva_pr(struct kvm *kvm, unsigned long hva, pte_t pte)
{ {
/* The page will get remapped properly on its next fault */ /* The page will get remapped properly on its next fault */
kvm_unmap_hva(kvm, hva); do_kvm_unmap_hva(kvm, hva, hva + PAGE_SIZE);
} }
/*****************************************/ /*****************************************/
@ -159,7 +238,7 @@ static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
vcpu->arch.shadow_msr = smsr; vcpu->arch.shadow_msr = smsr;
} }
void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
{ {
ulong old_msr = vcpu->arch.shared->msr; ulong old_msr = vcpu->arch.shared->msr;
@ -219,7 +298,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP); kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
} }
void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)
{ {
u32 host_pvr; u32 host_pvr;
@ -256,6 +335,23 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be")) if (!strcmp(cur_cpu_spec->platform, "ppc-cell-be"))
to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1); to_book3s(vcpu)->msr_mask &= ~(MSR_FE0 | MSR_FE1);
/*
* If they're asking for POWER6 or later, set the flag
* indicating that we can do multiple large page sizes
* and 1TB segments.
* Also set the flag that indicates that tlbie has the large
* page bit in the RB operand instead of the instruction.
*/
switch (PVR_VER(pvr)) {
case PVR_POWER6:
case PVR_POWER7:
case PVR_POWER7p:
case PVR_POWER8:
vcpu->arch.hflags |= BOOK3S_HFLAG_MULTI_PGSIZE |
BOOK3S_HFLAG_NEW_TLBIE;
break;
}
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
/* 32 bit Book3S always has 32 byte dcbz */ /* 32 bit Book3S always has 32 byte dcbz */
vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32;
@ -334,6 +430,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
ulong eaddr, int vec) ulong eaddr, int vec)
{ {
bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE);
bool iswrite = false;
int r = RESUME_GUEST; int r = RESUME_GUEST;
int relocated; int relocated;
int page_found = 0; int page_found = 0;
@ -344,10 +441,12 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
u64 vsid; u64 vsid;
relocated = data ? dr : ir; relocated = data ? dr : ir;
if (data && (vcpu->arch.fault_dsisr & DSISR_ISSTORE))
iswrite = true;
/* Resolve real address if translation turned on */ /* Resolve real address if translation turned on */
if (relocated) { if (relocated) {
page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data, iswrite);
} else { } else {
pte.may_execute = true; pte.may_execute = true;
pte.may_read = true; pte.may_read = true;
@ -355,6 +454,7 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
pte.raddr = eaddr & KVM_PAM; pte.raddr = eaddr & KVM_PAM;
pte.eaddr = eaddr; pte.eaddr = eaddr;
pte.vpage = eaddr >> 12; pte.vpage = eaddr >> 12;
pte.page_size = MMU_PAGE_64K;
} }
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
@ -388,22 +488,18 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
if (page_found == -ENOENT) { if (page_found == -ENOENT) {
/* Page not found in guest PTE entries */ /* Page not found in guest PTE entries */
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
vcpu->arch.shared->dsisr = svcpu->fault_dsisr; vcpu->arch.shared->dsisr = vcpu->arch.fault_dsisr;
vcpu->arch.shared->msr |= vcpu->arch.shared->msr |=
(svcpu->shadow_srr1 & 0x00000000f8000000ULL); vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL;
svcpu_put(svcpu);
kvmppc_book3s_queue_irqprio(vcpu, vec); kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EPERM) { } else if (page_found == -EPERM) {
/* Storage protection */ /* Storage protection */
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu); vcpu->arch.shared->dar = kvmppc_get_fault_dar(vcpu);
vcpu->arch.shared->dsisr = svcpu->fault_dsisr & ~DSISR_NOHPTE; vcpu->arch.shared->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE;
vcpu->arch.shared->dsisr |= DSISR_PROTFAULT; vcpu->arch.shared->dsisr |= DSISR_PROTFAULT;
vcpu->arch.shared->msr |= vcpu->arch.shared->msr |=
svcpu->shadow_srr1 & 0x00000000f8000000ULL; vcpu->arch.shadow_srr1 & 0x00000000f8000000ULL;
svcpu_put(svcpu);
kvmppc_book3s_queue_irqprio(vcpu, vec); kvmppc_book3s_queue_irqprio(vcpu, vec);
} else if (page_found == -EINVAL) { } else if (page_found == -EINVAL) {
/* Page not found in guest SLB */ /* Page not found in guest SLB */
@ -411,12 +507,20 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80);
} else if (!is_mmio && } else if (!is_mmio &&
kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) {
if (data && !(vcpu->arch.fault_dsisr & DSISR_NOHPTE)) {
/*
* There is already a host HPTE there, presumably
* a read-only one for a page the guest thinks
* is writable, so get rid of it first.
*/
kvmppc_mmu_unmap_page(vcpu, &pte);
}
/* The guest's PTE is not mapped yet. Map on the host */ /* The guest's PTE is not mapped yet. Map on the host */
kvmppc_mmu_map_page(vcpu, &pte); kvmppc_mmu_map_page(vcpu, &pte, iswrite);
if (data) if (data)
vcpu->stat.sp_storage++; vcpu->stat.sp_storage++;
else if (vcpu->arch.mmu.is_dcbz32(vcpu) && else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32)))
kvmppc_patch_dcbz(vcpu, &pte); kvmppc_patch_dcbz(vcpu, &pte);
} else { } else {
/* MMIO */ /* MMIO */
@ -619,13 +723,15 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
if (lost_ext & MSR_FP) if (lost_ext & MSR_FP)
kvmppc_load_up_fpu(); kvmppc_load_up_fpu();
#ifdef CONFIG_ALTIVEC
if (lost_ext & MSR_VEC) if (lost_ext & MSR_VEC)
kvmppc_load_up_altivec(); kvmppc_load_up_altivec();
#endif
current->thread.regs->msr |= lost_ext; current->thread.regs->msr |= lost_ext;
} }
int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int exit_nr) unsigned int exit_nr)
{ {
int r = RESUME_HOST; int r = RESUME_HOST;
int s; int s;
@ -643,25 +749,32 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
switch (exit_nr) { switch (exit_nr) {
case BOOK3S_INTERRUPT_INST_STORAGE: case BOOK3S_INTERRUPT_INST_STORAGE:
{ {
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); ulong shadow_srr1 = vcpu->arch.shadow_srr1;
ulong shadow_srr1 = svcpu->shadow_srr1;
vcpu->stat.pf_instruc++; vcpu->stat.pf_instruc++;
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
/* We set segments as unused segments when invalidating them. So /* We set segments as unused segments when invalidating them. So
* treat the respective fault as segment fault. */ * treat the respective fault as segment fault. */
if (svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT] == SR_INVALID) { {
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu)); struct kvmppc_book3s_shadow_vcpu *svcpu;
r = RESUME_GUEST; u32 sr;
svcpu = svcpu_get(vcpu);
sr = svcpu->sr[kvmppc_get_pc(vcpu) >> SID_SHIFT];
svcpu_put(svcpu); svcpu_put(svcpu);
break; if (sr == SR_INVALID) {
kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
r = RESUME_GUEST;
break;
}
} }
#endif #endif
svcpu_put(svcpu);
/* only care about PTEG not found errors, but leave NX alone */ /* only care about PTEG not found errors, but leave NX alone */
if (shadow_srr1 & 0x40000000) { if (shadow_srr1 & 0x40000000) {
int idx = srcu_read_lock(&vcpu->kvm->srcu);
r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr); r = kvmppc_handle_pagefault(run, vcpu, kvmppc_get_pc(vcpu), exit_nr);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
vcpu->stat.sp_instruc++; vcpu->stat.sp_instruc++;
} else if (vcpu->arch.mmu.is_dcbz32(vcpu) && } else if (vcpu->arch.mmu.is_dcbz32(vcpu) &&
(!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) {
@ -682,25 +795,36 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
case BOOK3S_INTERRUPT_DATA_STORAGE: case BOOK3S_INTERRUPT_DATA_STORAGE:
{ {
ulong dar = kvmppc_get_fault_dar(vcpu); ulong dar = kvmppc_get_fault_dar(vcpu);
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); u32 fault_dsisr = vcpu->arch.fault_dsisr;
u32 fault_dsisr = svcpu->fault_dsisr;
vcpu->stat.pf_storage++; vcpu->stat.pf_storage++;
#ifdef CONFIG_PPC_BOOK3S_32 #ifdef CONFIG_PPC_BOOK3S_32
/* We set segments as unused segments when invalidating them. So /* We set segments as unused segments when invalidating them. So
* treat the respective fault as segment fault. */ * treat the respective fault as segment fault. */
if ((svcpu->sr[dar >> SID_SHIFT]) == SR_INVALID) { {
kvmppc_mmu_map_segment(vcpu, dar); struct kvmppc_book3s_shadow_vcpu *svcpu;
r = RESUME_GUEST; u32 sr;
svcpu = svcpu_get(vcpu);
sr = svcpu->sr[dar >> SID_SHIFT];
svcpu_put(svcpu); svcpu_put(svcpu);
break; if (sr == SR_INVALID) {
kvmppc_mmu_map_segment(vcpu, dar);
r = RESUME_GUEST;
break;
}
} }
#endif #endif
svcpu_put(svcpu);
/* The only case we need to handle is missing shadow PTEs */ /*
if (fault_dsisr & DSISR_NOHPTE) { * We need to handle missing shadow PTEs, and
* protection faults due to us mapping a page read-only
* when the guest thinks it is writable.
*/
if (fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT)) {
int idx = srcu_read_lock(&vcpu->kvm->srcu);
r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr); r = kvmppc_handle_pagefault(run, vcpu, dar, exit_nr);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
} else { } else {
vcpu->arch.shared->dar = dar; vcpu->arch.shared->dar = dar;
vcpu->arch.shared->dsisr = fault_dsisr; vcpu->arch.shared->dsisr = fault_dsisr;
@ -743,13 +867,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
case BOOK3S_INTERRUPT_H_EMUL_ASSIST: case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
{ {
enum emulation_result er; enum emulation_result er;
struct kvmppc_book3s_shadow_vcpu *svcpu;
ulong flags; ulong flags;
program_interrupt: program_interrupt:
svcpu = svcpu_get(vcpu); flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
flags = svcpu->shadow_srr1 & 0x1f0000ull;
svcpu_put(svcpu);
if (vcpu->arch.shared->msr & MSR_PR) { if (vcpu->arch.shared->msr & MSR_PR) {
#ifdef EXIT_DEBUG #ifdef EXIT_DEBUG
@ -798,7 +919,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
ulong cmd = kvmppc_get_gpr(vcpu, 3); ulong cmd = kvmppc_get_gpr(vcpu, 3);
int i; int i;
#ifdef CONFIG_KVM_BOOK3S_64_PR #ifdef CONFIG_PPC_BOOK3S_64
if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) { if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) {
r = RESUME_GUEST; r = RESUME_GUEST;
break; break;
@ -881,9 +1002,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
break; break;
default: default:
{ {
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu); ulong shadow_srr1 = vcpu->arch.shadow_srr1;
ulong shadow_srr1 = svcpu->shadow_srr1;
svcpu_put(svcpu);
/* Ugh - bork here! What did we get? */ /* Ugh - bork here! What did we get? */
printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n",
exit_nr, kvmppc_get_pc(vcpu), shadow_srr1); exit_nr, kvmppc_get_pc(vcpu), shadow_srr1);
@ -920,8 +1039,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
return r; return r;
} }
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, static int kvm_arch_vcpu_ioctl_get_sregs_pr(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs) struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i; int i;
@ -947,13 +1066,13 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, static int kvm_arch_vcpu_ioctl_set_sregs_pr(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs) struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
int i; int i;
kvmppc_set_pvr(vcpu, sregs->pvr); kvmppc_set_pvr_pr(vcpu, sregs->pvr);
vcpu3s->sdr1 = sregs->u.s.sdr1; vcpu3s->sdr1 = sregs->u.s.sdr1;
if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) {
@ -983,7 +1102,8 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{ {
int r = 0; int r = 0;
@ -1012,7 +1132,8 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
return r; return r;
} }
int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val)
{ {
int r = 0; int r = 0;
@ -1042,28 +1163,30 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val)
return r; return r;
} }
int kvmppc_core_check_processor_compat(void) static struct kvm_vcpu *kvmppc_core_vcpu_create_pr(struct kvm *kvm,
{ unsigned int id)
return 0;
}
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s; struct kvmppc_vcpu_book3s *vcpu_book3s;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
int err = -ENOMEM; int err = -ENOMEM;
unsigned long p; unsigned long p;
vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s)); vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
if (!vcpu_book3s) if (!vcpu)
goto out; goto out;
vcpu_book3s->shadow_vcpu = vcpu_book3s = vzalloc(sizeof(struct kvmppc_vcpu_book3s));
kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL); if (!vcpu_book3s)
if (!vcpu_book3s->shadow_vcpu)
goto free_vcpu; goto free_vcpu;
vcpu->arch.book3s = vcpu_book3s;
#ifdef CONFIG_KVM_BOOK3S_32
vcpu->arch.shadow_vcpu =
kzalloc(sizeof(*vcpu->arch.shadow_vcpu), GFP_KERNEL);
if (!vcpu->arch.shadow_vcpu)
goto free_vcpu3s;
#endif
vcpu = &vcpu_book3s->vcpu;
err = kvm_vcpu_init(vcpu, kvm, id); err = kvm_vcpu_init(vcpu, kvm, id);
if (err) if (err)
goto free_shadow_vcpu; goto free_shadow_vcpu;
@ -1076,13 +1199,19 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096); vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096);
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
/* default to book3s_64 (970fx) */ /*
* Default to the same as the host if we're on sufficiently
* recent machine that we have 1TB segments;
* otherwise default to PPC970FX.
*/
vcpu->arch.pvr = 0x3C0301; vcpu->arch.pvr = 0x3C0301;
if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
vcpu->arch.pvr = mfspr(SPRN_PVR);
#else #else
/* default to book3s_32 (750) */ /* default to book3s_32 (750) */
vcpu->arch.pvr = 0x84202; vcpu->arch.pvr = 0x84202;
#endif #endif
kvmppc_set_pvr(vcpu, vcpu->arch.pvr); kvmppc_set_pvr_pr(vcpu, vcpu->arch.pvr);
vcpu->arch.slb_nr = 64; vcpu->arch.slb_nr = 64;
vcpu->arch.shadow_msr = MSR_USER64; vcpu->arch.shadow_msr = MSR_USER64;
@ -1096,24 +1225,31 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
uninit_vcpu: uninit_vcpu:
kvm_vcpu_uninit(vcpu); kvm_vcpu_uninit(vcpu);
free_shadow_vcpu: free_shadow_vcpu:
kfree(vcpu_book3s->shadow_vcpu); #ifdef CONFIG_KVM_BOOK3S_32
free_vcpu: kfree(vcpu->arch.shadow_vcpu);
free_vcpu3s:
#endif
vfree(vcpu_book3s); vfree(vcpu_book3s);
free_vcpu:
kmem_cache_free(kvm_vcpu_cache, vcpu);
out: out:
return ERR_PTR(err); return ERR_PTR(err);
} }
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_free_pr(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
free_page((unsigned long)vcpu->arch.shared & PAGE_MASK); free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
kvm_vcpu_uninit(vcpu); kvm_vcpu_uninit(vcpu);
kfree(vcpu_book3s->shadow_vcpu); #ifdef CONFIG_KVM_BOOK3S_32
kfree(vcpu->arch.shadow_vcpu);
#endif
vfree(vcpu_book3s); vfree(vcpu_book3s);
kmem_cache_free(kvm_vcpu_cache, vcpu);
} }
int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{ {
int ret; int ret;
struct thread_fp_state fp; struct thread_fp_state fp;
@ -1216,8 +1352,8 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
/* /*
* Get (and clear) the dirty memory log for a memory slot. * Get (and clear) the dirty memory log for a memory slot.
*/ */
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, static int kvm_vm_ioctl_get_dirty_log_pr(struct kvm *kvm,
struct kvm_dirty_log *log) struct kvm_dirty_log *log)
{ {
struct kvm_memory_slot *memslot; struct kvm_memory_slot *memslot;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
@ -1252,10 +1388,47 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
return r; return r;
} }
#ifdef CONFIG_PPC64 static void kvmppc_core_flush_memslot_pr(struct kvm *kvm,
int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info) struct kvm_memory_slot *memslot)
{ {
info->flags = KVM_PPC_1T_SEGMENTS; return;
}
static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_userspace_memory_region *mem)
{
return 0;
}
static void kvmppc_core_commit_memory_region_pr(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old)
{
return;
}
static void kvmppc_core_free_memslot_pr(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
return;
}
static int kvmppc_core_create_memslot_pr(struct kvm_memory_slot *slot,
unsigned long npages)
{
return 0;
}
#ifdef CONFIG_PPC64
static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm,
struct kvm_ppc_smmu_info *info)
{
long int i;
struct kvm_vcpu *vcpu;
info->flags = 0;
/* SLB is always 64 entries */ /* SLB is always 64 entries */
info->slb_size = 64; info->slb_size = 64;
@ -1266,53 +1439,49 @@ int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
info->sps[0].enc[0].page_shift = 12; info->sps[0].enc[0].page_shift = 12;
info->sps[0].enc[0].pte_enc = 0; info->sps[0].enc[0].pte_enc = 0;
/*
* 64k large page size.
* We only want to put this in if the CPUs we're emulating
* support it, but unfortunately we don't have a vcpu easily
* to hand here to test. Just pick the first vcpu, and if
* that doesn't exist yet, report the minimum capability,
* i.e., no 64k pages.
* 1T segment support goes along with 64k pages.
*/
i = 1;
vcpu = kvm_get_vcpu(kvm, 0);
if (vcpu && (vcpu->arch.hflags & BOOK3S_HFLAG_MULTI_PGSIZE)) {
info->flags = KVM_PPC_1T_SEGMENTS;
info->sps[i].page_shift = 16;
info->sps[i].slb_enc = SLB_VSID_L | SLB_VSID_LP_01;
info->sps[i].enc[0].page_shift = 16;
info->sps[i].enc[0].pte_enc = 1;
++i;
}
/* Standard 16M large page size segment */ /* Standard 16M large page size segment */
info->sps[1].page_shift = 24; info->sps[i].page_shift = 24;
info->sps[1].slb_enc = SLB_VSID_L; info->sps[i].slb_enc = SLB_VSID_L;
info->sps[1].enc[0].page_shift = 24; info->sps[i].enc[0].page_shift = 24;
info->sps[1].enc[0].pte_enc = 0; info->sps[i].enc[0].pte_enc = 0;
return 0; return 0;
} }
#else
static int kvm_vm_ioctl_get_smmu_info_pr(struct kvm *kvm,
struct kvm_ppc_smmu_info *info)
{
/* We should not get called */
BUG();
}
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
void kvmppc_core_free_memslot(struct kvm_memory_slot *free,
struct kvm_memory_slot *dont)
{
}
int kvmppc_core_create_memslot(struct kvm_memory_slot *slot,
unsigned long npages)
{
return 0;
}
int kvmppc_core_prepare_memory_region(struct kvm *kvm,
struct kvm_memory_slot *memslot,
struct kvm_userspace_memory_region *mem)
{
return 0;
}
void kvmppc_core_commit_memory_region(struct kvm *kvm,
struct kvm_userspace_memory_region *mem,
const struct kvm_memory_slot *old)
{
}
void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
{
}
static unsigned int kvm_global_user_count = 0; static unsigned int kvm_global_user_count = 0;
static DEFINE_SPINLOCK(kvm_global_user_count_lock); static DEFINE_SPINLOCK(kvm_global_user_count_lock);
int kvmppc_core_init_vm(struct kvm *kvm) static int kvmppc_core_init_vm_pr(struct kvm *kvm)
{ {
#ifdef CONFIG_PPC64 mutex_init(&kvm->arch.hpt_mutex);
INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
INIT_LIST_HEAD(&kvm->arch.rtas_tokens);
#endif
if (firmware_has_feature(FW_FEATURE_SET_MODE)) { if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
spin_lock(&kvm_global_user_count_lock); spin_lock(&kvm_global_user_count_lock);
@ -1323,7 +1492,7 @@ int kvmppc_core_init_vm(struct kvm *kvm)
return 0; return 0;
} }
void kvmppc_core_destroy_vm(struct kvm *kvm) static void kvmppc_core_destroy_vm_pr(struct kvm *kvm)
{ {
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables)); WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
@ -1338,26 +1507,81 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
} }
} }
static int kvmppc_book3s_init(void) static int kvmppc_core_check_processor_compat_pr(void)
{
/* we are always compatible */
return 0;
}
static long kvm_arch_vm_ioctl_pr(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
return -ENOTTY;
}
static struct kvmppc_ops kvm_ops_pr = {
.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_pr,
.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_pr,
.get_one_reg = kvmppc_get_one_reg_pr,
.set_one_reg = kvmppc_set_one_reg_pr,
.vcpu_load = kvmppc_core_vcpu_load_pr,
.vcpu_put = kvmppc_core_vcpu_put_pr,
.set_msr = kvmppc_set_msr_pr,
.vcpu_run = kvmppc_vcpu_run_pr,
.vcpu_create = kvmppc_core_vcpu_create_pr,
.vcpu_free = kvmppc_core_vcpu_free_pr,
.check_requests = kvmppc_core_check_requests_pr,
.get_dirty_log = kvm_vm_ioctl_get_dirty_log_pr,
.flush_memslot = kvmppc_core_flush_memslot_pr,
.prepare_memory_region = kvmppc_core_prepare_memory_region_pr,
.commit_memory_region = kvmppc_core_commit_memory_region_pr,
.unmap_hva = kvm_unmap_hva_pr,
.unmap_hva_range = kvm_unmap_hva_range_pr,
.age_hva = kvm_age_hva_pr,
.test_age_hva = kvm_test_age_hva_pr,
.set_spte_hva = kvm_set_spte_hva_pr,
.mmu_destroy = kvmppc_mmu_destroy_pr,
.free_memslot = kvmppc_core_free_memslot_pr,
.create_memslot = kvmppc_core_create_memslot_pr,
.init_vm = kvmppc_core_init_vm_pr,
.destroy_vm = kvmppc_core_destroy_vm_pr,
.get_smmu_info = kvm_vm_ioctl_get_smmu_info_pr,
.emulate_op = kvmppc_core_emulate_op_pr,
.emulate_mtspr = kvmppc_core_emulate_mtspr_pr,
.emulate_mfspr = kvmppc_core_emulate_mfspr_pr,
.fast_vcpu_kick = kvm_vcpu_kick,
.arch_vm_ioctl = kvm_arch_vm_ioctl_pr,
};
int kvmppc_book3s_init_pr(void)
{ {
int r; int r;
r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), 0, r = kvmppc_core_check_processor_compat_pr();
THIS_MODULE); if (r < 0)
if (r)
return r; return r;
r = kvmppc_mmu_hpte_sysinit(); kvm_ops_pr.owner = THIS_MODULE;
kvmppc_pr_ops = &kvm_ops_pr;
r = kvmppc_mmu_hpte_sysinit();
return r; return r;
} }
static void kvmppc_book3s_exit(void) void kvmppc_book3s_exit_pr(void)
{ {
kvmppc_pr_ops = NULL;
kvmppc_mmu_hpte_sysexit(); kvmppc_mmu_hpte_sysexit();
kvm_exit();
} }
module_init(kvmppc_book3s_init); /*
module_exit(kvmppc_book3s_exit); * We only support separate modules for book3s 64
*/
#ifdef CONFIG_PPC_BOOK3S_64
module_init(kvmppc_book3s_init_pr);
module_exit(kvmppc_book3s_exit_pr);
MODULE_LICENSE("GPL");
#endif

View file

@ -21,6 +21,8 @@
#include <asm/kvm_ppc.h> #include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h> #include <asm/kvm_book3s.h>
#define HPTE_SIZE 16 /* bytes per HPT entry */
static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index) static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index)
{ {
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
@ -40,32 +42,41 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
long pte_index = kvmppc_get_gpr(vcpu, 5); long pte_index = kvmppc_get_gpr(vcpu, 5);
unsigned long pteg[2 * 8]; unsigned long pteg[2 * 8];
unsigned long pteg_addr, i, *hpte; unsigned long pteg_addr, i, *hpte;
long int ret;
i = pte_index & 7;
pte_index &= ~7UL; pte_index &= ~7UL;
pteg_addr = get_pteg_addr(vcpu, pte_index); pteg_addr = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
hpte = pteg; hpte = pteg;
ret = H_PTEG_FULL;
if (likely((flags & H_EXACT) == 0)) { if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7UL;
for (i = 0; ; ++i) { for (i = 0; ; ++i) {
if (i == 8) if (i == 8)
return H_PTEG_FULL; goto done;
if ((*hpte & HPTE_V_VALID) == 0) if ((*hpte & HPTE_V_VALID) == 0)
break; break;
hpte += 2; hpte += 2;
} }
} else { } else {
i = kvmppc_get_gpr(vcpu, 5) & 7UL;
hpte += i * 2; hpte += i * 2;
if (*hpte & HPTE_V_VALID)
goto done;
} }
hpte[0] = kvmppc_get_gpr(vcpu, 6); hpte[0] = kvmppc_get_gpr(vcpu, 6);
hpte[1] = kvmppc_get_gpr(vcpu, 7); hpte[1] = kvmppc_get_gpr(vcpu, 7);
copy_to_user((void __user *)pteg_addr, pteg, sizeof(pteg)); pteg_addr += i * HPTE_SIZE;
kvmppc_set_gpr(vcpu, 3, H_SUCCESS); copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
kvmppc_set_gpr(vcpu, 4, pte_index | i); kvmppc_set_gpr(vcpu, 4, pte_index | i);
ret = H_SUCCESS;
done:
mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
kvmppc_set_gpr(vcpu, 3, ret);
return EMULATE_DONE; return EMULATE_DONE;
} }
@ -77,26 +88,31 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
unsigned long avpn = kvmppc_get_gpr(vcpu, 6); unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
unsigned long v = 0, pteg, rb; unsigned long v = 0, pteg, rb;
unsigned long pte[2]; unsigned long pte[2];
long int ret;
pteg = get_pteg_addr(vcpu, pte_index); pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
copy_from_user(pte, (void __user *)pteg, sizeof(pte)); copy_from_user(pte, (void __user *)pteg, sizeof(pte));
ret = H_NOT_FOUND;
if ((pte[0] & HPTE_V_VALID) == 0 || if ((pte[0] & HPTE_V_VALID) == 0 ||
((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn) || ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn) ||
((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) { ((flags & H_ANDCOND) && (pte[0] & avpn) != 0))
kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND); goto done;
return EMULATE_DONE;
}
copy_to_user((void __user *)pteg, &v, sizeof(v)); copy_to_user((void __user *)pteg, &v, sizeof(v));
rb = compute_tlbie_rb(pte[0], pte[1], pte_index); rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
kvmppc_set_gpr(vcpu, 3, H_SUCCESS); ret = H_SUCCESS;
kvmppc_set_gpr(vcpu, 4, pte[0]); kvmppc_set_gpr(vcpu, 4, pte[0]);
kvmppc_set_gpr(vcpu, 5, pte[1]); kvmppc_set_gpr(vcpu, 5, pte[1]);
done:
mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
kvmppc_set_gpr(vcpu, 3, ret);
return EMULATE_DONE; return EMULATE_DONE;
} }
@ -124,6 +140,7 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
int paramnr = 4; int paramnr = 4;
int ret = H_SUCCESS; int ret = H_SUCCESS;
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
unsigned long tsh = kvmppc_get_gpr(vcpu, paramnr+(2*i)); unsigned long tsh = kvmppc_get_gpr(vcpu, paramnr+(2*i));
unsigned long tsl = kvmppc_get_gpr(vcpu, paramnr+(2*i)+1); unsigned long tsl = kvmppc_get_gpr(vcpu, paramnr+(2*i)+1);
@ -172,6 +189,7 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
} }
kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh); kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
} }
mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
kvmppc_set_gpr(vcpu, 3, ret); kvmppc_set_gpr(vcpu, 3, ret);
return EMULATE_DONE; return EMULATE_DONE;
@ -184,15 +202,16 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
unsigned long avpn = kvmppc_get_gpr(vcpu, 6); unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
unsigned long rb, pteg, r, v; unsigned long rb, pteg, r, v;
unsigned long pte[2]; unsigned long pte[2];
long int ret;
pteg = get_pteg_addr(vcpu, pte_index); pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
copy_from_user(pte, (void __user *)pteg, sizeof(pte)); copy_from_user(pte, (void __user *)pteg, sizeof(pte));
ret = H_NOT_FOUND;
if ((pte[0] & HPTE_V_VALID) == 0 || if ((pte[0] & HPTE_V_VALID) == 0 ||
((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn)) { ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn))
kvmppc_set_gpr(vcpu, 3, H_NOT_FOUND); goto done;
return EMULATE_DONE;
}
v = pte[0]; v = pte[0];
r = pte[1]; r = pte[1];
@ -207,8 +226,11 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
rb = compute_tlbie_rb(v, r, pte_index); rb = compute_tlbie_rb(v, r, pte_index);
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
copy_to_user((void __user *)pteg, pte, sizeof(pte)); copy_to_user((void __user *)pteg, pte, sizeof(pte));
ret = H_SUCCESS;
kvmppc_set_gpr(vcpu, 3, H_SUCCESS); done:
mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
kvmppc_set_gpr(vcpu, 3, ret);
return EMULATE_DONE; return EMULATE_DONE;
} }

View file

@ -38,32 +38,6 @@
#define FUNC(name) GLUE(.,name) #define FUNC(name) GLUE(.,name)
.globl kvmppc_skip_interrupt
kvmppc_skip_interrupt:
/*
* Here all GPRs are unchanged from when the interrupt happened
* except for r13, which is saved in SPRG_SCRATCH0.
*/
mfspr r13, SPRN_SRR0
addi r13, r13, 4
mtspr SPRN_SRR0, r13
GET_SCRATCH0(r13)
rfid
b .
.globl kvmppc_skip_Hinterrupt
kvmppc_skip_Hinterrupt:
/*
* Here all GPRs are unchanged from when the interrupt happened
* except for r13, which is saved in SPRG_SCRATCH0.
*/
mfspr r13, SPRN_HSRR0
addi r13, r13, 4
mtspr SPRN_HSRR0, r13
GET_SCRATCH0(r13)
hrfid
b .
#elif defined(CONFIG_PPC_BOOK3S_32) #elif defined(CONFIG_PPC_BOOK3S_32)
#define FUNC(name) name #define FUNC(name) name
@ -179,11 +153,15 @@ _GLOBAL(kvmppc_entry_trampoline)
li r6, MSR_IR | MSR_DR li r6, MSR_IR | MSR_DR
andc r6, r5, r6 /* Clear DR and IR in MSR value */ andc r6, r5, r6 /* Clear DR and IR in MSR value */
#ifdef CONFIG_PPC_BOOK3S_32
/* /*
* Set EE in HOST_MSR so that it's enabled when we get into our * Set EE in HOST_MSR so that it's enabled when we get into our
* C exit handler function * C exit handler function. On 64-bit we delay enabling
* interrupts until we have finished transferring stuff
* to or from the PACA.
*/ */
ori r5, r5, MSR_EE ori r5, r5, MSR_EE
#endif
mtsrr0 r7 mtsrr0 r7
mtsrr1 r6 mtsrr1 r6
RFI RFI

View file

@ -260,6 +260,7 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
*/ */
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(kvmppc_rtas_hcall);
void kvmppc_rtas_tokens_free(struct kvm *kvm) void kvmppc_rtas_tokens_free(struct kvm *kvm)
{ {

View file

@ -161,8 +161,8 @@ kvmppc_handler_trampoline_enter_end:
.global kvmppc_handler_trampoline_exit .global kvmppc_handler_trampoline_exit
kvmppc_handler_trampoline_exit: kvmppc_handler_trampoline_exit:
.global kvmppc_interrupt .global kvmppc_interrupt_pr
kvmppc_interrupt: kvmppc_interrupt_pr:
/* Register usage at this point: /* Register usage at this point:
* *

View file

@ -818,7 +818,7 @@ int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
} }
/* Check for real mode returning too hard */ /* Check for real mode returning too hard */
if (xics->real_mode) if (xics->real_mode && is_kvmppc_hv_enabled(vcpu->kvm))
return kvmppc_xics_rm_complete(vcpu, req); return kvmppc_xics_rm_complete(vcpu, req);
switch (req) { switch (req) {
@ -840,6 +840,7 @@ int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(kvmppc_xics_hcall);
/* -- Initialisation code etc. -- */ /* -- Initialisation code etc. -- */
@ -1250,13 +1251,13 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
xics_debugfs_init(xics); xics_debugfs_init(xics);
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
if (cpu_has_feature(CPU_FTR_ARCH_206)) { if (cpu_has_feature(CPU_FTR_ARCH_206)) {
/* Enable real mode support */ /* Enable real mode support */
xics->real_mode = ENABLE_REALMODE; xics->real_mode = ENABLE_REALMODE;
xics->real_mode_dbg = DEBUG_REALMODE; xics->real_mode_dbg = DEBUG_REALMODE;
} }
#endif /* CONFIG_KVM_BOOK3S_64_HV */ #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
return 0; return 0;
} }

View file

@ -40,7 +40,9 @@
#include "timing.h" #include "timing.h"
#include "booke.h" #include "booke.h"
#include "trace.h"
#define CREATE_TRACE_POINTS
#include "trace_booke.h"
unsigned long kvmppc_booke_handlers; unsigned long kvmppc_booke_handlers;
@ -133,6 +135,29 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
#endif #endif
} }
static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu)
{
/* Synchronize guest's desire to get debug interrupts into shadow MSR */
#ifndef CONFIG_KVM_BOOKE_HV
vcpu->arch.shadow_msr &= ~MSR_DE;
vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_DE;
#endif
/* Force enable debug interrupts when user space wants to debug */
if (vcpu->guest_debug) {
#ifdef CONFIG_KVM_BOOKE_HV
/*
* Since there is no shadow MSR, sync MSR_DE into the guest
* visible MSR.
*/
vcpu->arch.shared->msr |= MSR_DE;
#else
vcpu->arch.shadow_msr |= MSR_DE;
vcpu->arch.shared->msr &= ~MSR_DE;
#endif
}
}
/* /*
* Helper function for "full" MSR writes. No need to call this if only * Helper function for "full" MSR writes. No need to call this if only
* EE/CE/ME/DE/RI are changing. * EE/CE/ME/DE/RI are changing.
@ -150,6 +175,7 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
kvmppc_mmu_msr_notify(vcpu, old_msr); kvmppc_mmu_msr_notify(vcpu, old_msr);
kvmppc_vcpu_sync_spe(vcpu); kvmppc_vcpu_sync_spe(vcpu);
kvmppc_vcpu_sync_fpu(vcpu); kvmppc_vcpu_sync_fpu(vcpu);
kvmppc_vcpu_sync_debug(vcpu);
} }
static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu, static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
@ -655,6 +681,7 @@ int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{ {
int ret, s; int ret, s;
struct thread_struct thread;
#ifdef CONFIG_PPC_FPU #ifdef CONFIG_PPC_FPU
struct thread_fp_state fp; struct thread_fp_state fp;
int fpexc_mode; int fpexc_mode;
@ -695,6 +722,12 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
kvmppc_load_guest_fp(vcpu); kvmppc_load_guest_fp(vcpu);
#endif #endif
/* Switch to guest debug context */
thread.debug = vcpu->arch.shadow_dbg_reg;
switch_booke_debug_regs(&thread);
thread.debug = current->thread.debug;
current->thread.debug = vcpu->arch.shadow_dbg_reg;
kvmppc_fix_ee_before_entry(); kvmppc_fix_ee_before_entry();
ret = __kvmppc_vcpu_run(kvm_run, vcpu); ret = __kvmppc_vcpu_run(kvm_run, vcpu);
@ -702,6 +735,10 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
/* No need for kvm_guest_exit. It's done in handle_exit. /* No need for kvm_guest_exit. It's done in handle_exit.
We also get here with interrupts enabled. */ We also get here with interrupts enabled. */
/* Switch back to user space debug context */
switch_booke_debug_regs(&thread);
current->thread.debug = thread.debug;
#ifdef CONFIG_PPC_FPU #ifdef CONFIG_PPC_FPU
kvmppc_save_guest_fp(vcpu); kvmppc_save_guest_fp(vcpu);
@ -757,6 +794,30 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
} }
} }
static int kvmppc_handle_debug(struct kvm_run *run, struct kvm_vcpu *vcpu)
{
struct debug_reg *dbg_reg = &(vcpu->arch.shadow_dbg_reg);
u32 dbsr = vcpu->arch.dbsr;
run->debug.arch.status = 0;
run->debug.arch.address = vcpu->arch.pc;
if (dbsr & (DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4)) {
run->debug.arch.status |= KVMPPC_DEBUG_BREAKPOINT;
} else {
if (dbsr & (DBSR_DAC1W | DBSR_DAC2W))
run->debug.arch.status |= KVMPPC_DEBUG_WATCH_WRITE;
else if (dbsr & (DBSR_DAC1R | DBSR_DAC2R))
run->debug.arch.status |= KVMPPC_DEBUG_WATCH_READ;
if (dbsr & (DBSR_DAC1R | DBSR_DAC1W))
run->debug.arch.address = dbg_reg->dac1;
else if (dbsr & (DBSR_DAC2R | DBSR_DAC2W))
run->debug.arch.address = dbg_reg->dac2;
}
return RESUME_HOST;
}
static void kvmppc_fill_pt_regs(struct pt_regs *regs) static void kvmppc_fill_pt_regs(struct pt_regs *regs)
{ {
ulong r1, ip, msr, lr; ulong r1, ip, msr, lr;
@ -817,6 +878,11 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
case BOOKE_INTERRUPT_CRITICAL: case BOOKE_INTERRUPT_CRITICAL:
unknown_exception(&regs); unknown_exception(&regs);
break; break;
case BOOKE_INTERRUPT_DEBUG:
/* Save DBSR before preemption is enabled */
vcpu->arch.dbsr = mfspr(SPRN_DBSR);
kvmppc_clear_dbsr();
break;
} }
} }
@ -1134,18 +1200,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
} }
case BOOKE_INTERRUPT_DEBUG: { case BOOKE_INTERRUPT_DEBUG: {
u32 dbsr; r = kvmppc_handle_debug(run, vcpu);
if (r == RESUME_HOST)
vcpu->arch.pc = mfspr(SPRN_CSRR0); run->exit_reason = KVM_EXIT_DEBUG;
/* clear IAC events in DBSR register */
dbsr = mfspr(SPRN_DBSR);
dbsr &= DBSR_IAC1 | DBSR_IAC2 | DBSR_IAC3 | DBSR_IAC4;
mtspr(SPRN_DBSR, dbsr);
run->exit_reason = KVM_EXIT_DEBUG;
kvmppc_account_exit(vcpu, DEBUG_EXITS); kvmppc_account_exit(vcpu, DEBUG_EXITS);
r = RESUME_HOST;
break; break;
} }
@ -1196,7 +1254,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
kvmppc_set_msr(vcpu, 0); kvmppc_set_msr(vcpu, 0);
#ifndef CONFIG_KVM_BOOKE_HV #ifndef CONFIG_KVM_BOOKE_HV
vcpu->arch.shadow_msr = MSR_USER | MSR_DE | MSR_IS | MSR_DS; vcpu->arch.shadow_msr = MSR_USER | MSR_IS | MSR_DS;
vcpu->arch.shadow_pid = 1; vcpu->arch.shadow_pid = 1;
vcpu->arch.shared->msr = 0; vcpu->arch.shared->msr = 0;
#endif #endif
@ -1358,7 +1416,7 @@ static int set_sregs_arch206(struct kvm_vcpu *vcpu,
return 0; return 0;
} }
void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) int kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
{ {
sregs->u.e.features |= KVM_SREGS_E_IVOR; sregs->u.e.features |= KVM_SREGS_E_IVOR;
@ -1378,6 +1436,7 @@ void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
sregs->u.e.ivor_low[13] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]; sregs->u.e.ivor_low[13] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS];
sregs->u.e.ivor_low[14] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]; sregs->u.e.ivor_low[14] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS];
sregs->u.e.ivor_low[15] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]; sregs->u.e.ivor_low[15] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG];
return 0;
} }
int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
@ -1412,8 +1471,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
get_sregs_base(vcpu, sregs); get_sregs_base(vcpu, sregs);
get_sregs_arch206(vcpu, sregs); get_sregs_arch206(vcpu, sregs);
kvmppc_core_get_sregs(vcpu, sregs); return vcpu->kvm->arch.kvm_ops->get_sregs(vcpu, sregs);
return 0;
} }
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
@ -1432,7 +1490,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
if (ret < 0) if (ret < 0)
return ret; return ret;
return kvmppc_core_set_sregs(vcpu, sregs); return vcpu->kvm->arch.kvm_ops->set_sregs(vcpu, sregs);
} }
int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
@ -1440,7 +1498,6 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
int r = 0; int r = 0;
union kvmppc_one_reg val; union kvmppc_one_reg val;
int size; int size;
long int i;
size = one_reg_size(reg->id); size = one_reg_size(reg->id);
if (size > sizeof(val)) if (size > sizeof(val))
@ -1448,16 +1505,24 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
switch (reg->id) { switch (reg->id) {
case KVM_REG_PPC_IAC1: case KVM_REG_PPC_IAC1:
case KVM_REG_PPC_IAC2: val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac1);
case KVM_REG_PPC_IAC3:
case KVM_REG_PPC_IAC4:
i = reg->id - KVM_REG_PPC_IAC1;
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac[i]);
break; break;
case KVM_REG_PPC_IAC2:
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac2);
break;
#if CONFIG_PPC_ADV_DEBUG_IACS > 2
case KVM_REG_PPC_IAC3:
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac3);
break;
case KVM_REG_PPC_IAC4:
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.iac4);
break;
#endif
case KVM_REG_PPC_DAC1: case KVM_REG_PPC_DAC1:
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac1);
break;
case KVM_REG_PPC_DAC2: case KVM_REG_PPC_DAC2:
i = reg->id - KVM_REG_PPC_DAC1; val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac2);
val = get_reg_val(reg->id, vcpu->arch.dbg_reg.dac[i]);
break; break;
case KVM_REG_PPC_EPR: { case KVM_REG_PPC_EPR: {
u32 epr = get_guest_epr(vcpu); u32 epr = get_guest_epr(vcpu);
@ -1476,10 +1541,13 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
val = get_reg_val(reg->id, vcpu->arch.tsr); val = get_reg_val(reg->id, vcpu->arch.tsr);
break; break;
case KVM_REG_PPC_DEBUG_INST: case KVM_REG_PPC_DEBUG_INST:
val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV); val = get_reg_val(reg->id, KVMPPC_INST_EHPRIV_DEBUG);
break;
case KVM_REG_PPC_VRSAVE:
val = get_reg_val(reg->id, vcpu->arch.vrsave);
break; break;
default: default:
r = kvmppc_get_one_reg(vcpu, reg->id, &val); r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, reg->id, &val);
break; break;
} }
@ -1497,7 +1565,6 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
int r = 0; int r = 0;
union kvmppc_one_reg val; union kvmppc_one_reg val;
int size; int size;
long int i;
size = one_reg_size(reg->id); size = one_reg_size(reg->id);
if (size > sizeof(val)) if (size > sizeof(val))
@ -1508,16 +1575,24 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
switch (reg->id) { switch (reg->id) {
case KVM_REG_PPC_IAC1: case KVM_REG_PPC_IAC1:
case KVM_REG_PPC_IAC2: vcpu->arch.dbg_reg.iac1 = set_reg_val(reg->id, val);
case KVM_REG_PPC_IAC3:
case KVM_REG_PPC_IAC4:
i = reg->id - KVM_REG_PPC_IAC1;
vcpu->arch.dbg_reg.iac[i] = set_reg_val(reg->id, val);
break; break;
case KVM_REG_PPC_IAC2:
vcpu->arch.dbg_reg.iac2 = set_reg_val(reg->id, val);
break;
#if CONFIG_PPC_ADV_DEBUG_IACS > 2
case KVM_REG_PPC_IAC3:
vcpu->arch.dbg_reg.iac3 = set_reg_val(reg->id, val);
break;
case KVM_REG_PPC_IAC4:
vcpu->arch.dbg_reg.iac4 = set_reg_val(reg->id, val);
break;
#endif
case KVM_REG_PPC_DAC1: case KVM_REG_PPC_DAC1:
vcpu->arch.dbg_reg.dac1 = set_reg_val(reg->id, val);
break;
case KVM_REG_PPC_DAC2: case KVM_REG_PPC_DAC2:
i = reg->id - KVM_REG_PPC_DAC1; vcpu->arch.dbg_reg.dac2 = set_reg_val(reg->id, val);
vcpu->arch.dbg_reg.dac[i] = set_reg_val(reg->id, val);
break; break;
case KVM_REG_PPC_EPR: { case KVM_REG_PPC_EPR: {
u32 new_epr = set_reg_val(reg->id, val); u32 new_epr = set_reg_val(reg->id, val);
@ -1551,20 +1626,17 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
kvmppc_set_tcr(vcpu, tcr); kvmppc_set_tcr(vcpu, tcr);
break; break;
} }
case KVM_REG_PPC_VRSAVE:
vcpu->arch.vrsave = set_reg_val(reg->id, val);
break;
default: default:
r = kvmppc_set_one_reg(vcpu, reg->id, &val); r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, reg->id, &val);
break; break;
} }
return r; return r;
} }
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
return -EINVAL;
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{ {
return -ENOTSUPP; return -ENOTSUPP;
@ -1589,12 +1661,12 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
return -ENOTSUPP; return -ENOTSUPP;
} }
void kvmppc_core_free_memslot(struct kvm_memory_slot *free, void kvmppc_core_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
} }
int kvmppc_core_create_memslot(struct kvm_memory_slot *slot, int kvmppc_core_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages) unsigned long npages)
{ {
return 0; return 0;
@ -1670,6 +1742,157 @@ void kvmppc_decrementer_func(unsigned long data)
kvmppc_set_tsr_bits(vcpu, TSR_DIS); kvmppc_set_tsr_bits(vcpu, TSR_DIS);
} }
static int kvmppc_booke_add_breakpoint(struct debug_reg *dbg_reg,
uint64_t addr, int index)
{
switch (index) {
case 0:
dbg_reg->dbcr0 |= DBCR0_IAC1;
dbg_reg->iac1 = addr;
break;
case 1:
dbg_reg->dbcr0 |= DBCR0_IAC2;
dbg_reg->iac2 = addr;
break;
#if CONFIG_PPC_ADV_DEBUG_IACS > 2
case 2:
dbg_reg->dbcr0 |= DBCR0_IAC3;
dbg_reg->iac3 = addr;
break;
case 3:
dbg_reg->dbcr0 |= DBCR0_IAC4;
dbg_reg->iac4 = addr;
break;
#endif
default:
return -EINVAL;
}
dbg_reg->dbcr0 |= DBCR0_IDM;
return 0;
}
static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr,
int type, int index)
{
switch (index) {
case 0:
if (type & KVMPPC_DEBUG_WATCH_READ)
dbg_reg->dbcr0 |= DBCR0_DAC1R;
if (type & KVMPPC_DEBUG_WATCH_WRITE)
dbg_reg->dbcr0 |= DBCR0_DAC1W;
dbg_reg->dac1 = addr;
break;
case 1:
if (type & KVMPPC_DEBUG_WATCH_READ)
dbg_reg->dbcr0 |= DBCR0_DAC2R;
if (type & KVMPPC_DEBUG_WATCH_WRITE)
dbg_reg->dbcr0 |= DBCR0_DAC2W;
dbg_reg->dac2 = addr;
break;
default:
return -EINVAL;
}
dbg_reg->dbcr0 |= DBCR0_IDM;
return 0;
}
void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, bool set)
{
/* XXX: Add similar MSR protection for BookE-PR */
#ifdef CONFIG_KVM_BOOKE_HV
BUG_ON(prot_bitmap & ~(MSRP_UCLEP | MSRP_DEP | MSRP_PMMP));
if (set) {
if (prot_bitmap & MSR_UCLE)
vcpu->arch.shadow_msrp |= MSRP_UCLEP;
if (prot_bitmap & MSR_DE)
vcpu->arch.shadow_msrp |= MSRP_DEP;
if (prot_bitmap & MSR_PMM)
vcpu->arch.shadow_msrp |= MSRP_PMMP;
} else {
if (prot_bitmap & MSR_UCLE)
vcpu->arch.shadow_msrp &= ~MSRP_UCLEP;
if (prot_bitmap & MSR_DE)
vcpu->arch.shadow_msrp &= ~MSRP_DEP;
if (prot_bitmap & MSR_PMM)
vcpu->arch.shadow_msrp &= ~MSRP_PMMP;
}
#endif
}
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
struct kvm_guest_debug *dbg)
{
struct debug_reg *dbg_reg;
int n, b = 0, w = 0;
if (!(dbg->control & KVM_GUESTDBG_ENABLE)) {
vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
vcpu->guest_debug = 0;
kvm_guest_protect_msr(vcpu, MSR_DE, false);
return 0;
}
kvm_guest_protect_msr(vcpu, MSR_DE, true);
vcpu->guest_debug = dbg->control;
vcpu->arch.shadow_dbg_reg.dbcr0 = 0;
/* Set DBCR0_EDM in guest visible DBCR0 register. */
vcpu->arch.dbg_reg.dbcr0 = DBCR0_EDM;
if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP)
vcpu->arch.shadow_dbg_reg.dbcr0 |= DBCR0_IDM | DBCR0_IC;
/* Code below handles only HW breakpoints */
dbg_reg = &(vcpu->arch.shadow_dbg_reg);
#ifdef CONFIG_KVM_BOOKE_HV
/*
* On BookE-HV (e500mc) the guest is always executed with MSR.GS=1
* DBCR1 and DBCR2 are set to trigger debug events when MSR.PR is 0
*/
dbg_reg->dbcr1 = 0;
dbg_reg->dbcr2 = 0;
#else
/*
* On BookE-PR (e500v2) the guest is always executed with MSR.PR=1
* We set DBCR1 and DBCR2 to only trigger debug events when MSR.PR
* is set.
*/
dbg_reg->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | DBCR1_IAC3US |
DBCR1_IAC4US;
dbg_reg->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US;
#endif
if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
return 0;
for (n = 0; n < (KVMPPC_BOOKE_IAC_NUM + KVMPPC_BOOKE_DAC_NUM); n++) {
uint64_t addr = dbg->arch.bp[n].addr;
uint32_t type = dbg->arch.bp[n].type;
if (type == KVMPPC_DEBUG_NONE)
continue;
if (type & !(KVMPPC_DEBUG_WATCH_READ |
KVMPPC_DEBUG_WATCH_WRITE |
KVMPPC_DEBUG_BREAKPOINT))
return -EINVAL;
if (type & KVMPPC_DEBUG_BREAKPOINT) {
/* Setting H/W breakpoint */
if (kvmppc_booke_add_breakpoint(dbg_reg, addr, b++))
return -EINVAL;
} else {
/* Setting H/W watchpoint */
if (kvmppc_booke_add_watchpoint(dbg_reg, addr,
type, w++))
return -EINVAL;
}
}
return 0;
}
void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu) void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{ {
vcpu->cpu = smp_processor_id(); vcpu->cpu = smp_processor_id();
@ -1680,6 +1903,44 @@ void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu)
{ {
current->thread.kvm_vcpu = NULL; current->thread.kvm_vcpu = NULL;
vcpu->cpu = -1; vcpu->cpu = -1;
/* Clear pending debug event in DBSR */
kvmppc_clear_dbsr();
}
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->mmu_destroy(vcpu);
}
int kvmppc_core_init_vm(struct kvm *kvm)
{
return kvm->arch.kvm_ops->init_vm(kvm);
}
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{
return kvm->arch.kvm_ops->vcpu_create(kvm, id);
}
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_free(vcpu);
}
void kvmppc_core_destroy_vm(struct kvm *kvm)
{
kvm->arch.kvm_ops->destroy_vm(kvm);
}
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_load(vcpu, cpu);
}
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
{
vcpu->kvm->arch.kvm_ops->vcpu_put(vcpu);
} }
int __init kvmppc_booke_init(void) int __init kvmppc_booke_init(void)

View file

@ -99,6 +99,30 @@ enum int_class {
void kvmppc_set_pending_interrupt(struct kvm_vcpu *vcpu, enum int_class type); void kvmppc_set_pending_interrupt(struct kvm_vcpu *vcpu, enum int_class type);
extern void kvmppc_mmu_destroy_44x(struct kvm_vcpu *vcpu);
extern int kvmppc_core_emulate_op_44x(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance);
extern int kvmppc_core_emulate_mtspr_44x(struct kvm_vcpu *vcpu, int sprn,
ulong spr_val);
extern int kvmppc_core_emulate_mfspr_44x(struct kvm_vcpu *vcpu, int sprn,
ulong *spr_val);
extern void kvmppc_mmu_destroy_e500(struct kvm_vcpu *vcpu);
extern int kvmppc_core_emulate_op_e500(struct kvm_run *run,
struct kvm_vcpu *vcpu,
unsigned int inst, int *advance);
extern int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn,
ulong spr_val);
extern int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn,
ulong *spr_val);
extern void kvmppc_mmu_destroy_e500(struct kvm_vcpu *vcpu);
extern int kvmppc_core_emulate_op_e500(struct kvm_run *run,
struct kvm_vcpu *vcpu,
unsigned int inst, int *advance);
extern int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn,
ulong spr_val);
extern int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn,
ulong *spr_val);
/* /*
* Load up guest vcpu FP state if it's needed. * Load up guest vcpu FP state if it's needed.
* It also set the MSR_FP in thread so that host know * It also set the MSR_FP in thread so that host know
@ -129,4 +153,9 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
giveup_fpu(current); giveup_fpu(current);
#endif #endif
} }
static inline void kvmppc_clear_dbsr(void)
{
mtspr(SPRN_DBSR, mfspr(SPRN_DBSR));
}
#endif /* __KVM_BOOKE_H__ */ #endif /* __KVM_BOOKE_H__ */

View file

@ -305,7 +305,7 @@ void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu)
{ {
} }
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) static void kvmppc_core_vcpu_load_e500(struct kvm_vcpu *vcpu, int cpu)
{ {
kvmppc_booke_vcpu_load(vcpu, cpu); kvmppc_booke_vcpu_load(vcpu, cpu);
@ -313,7 +313,7 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvmppc_e500_recalc_shadow_pid(to_e500(vcpu)); kvmppc_e500_recalc_shadow_pid(to_e500(vcpu));
} }
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_put_e500(struct kvm_vcpu *vcpu)
{ {
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
if (vcpu->arch.shadow_msr & MSR_SPE) if (vcpu->arch.shadow_msr & MSR_SPE)
@ -367,7 +367,8 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_get_sregs_e500(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@ -388,9 +389,11 @@ void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
kvmppc_get_sregs_ivor(vcpu, sregs); kvmppc_get_sregs_ivor(vcpu, sregs);
kvmppc_get_sregs_e500_tlb(vcpu, sregs); kvmppc_get_sregs_e500_tlb(vcpu, sregs);
return 0;
} }
int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_set_sregs_e500(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
int ret; int ret;
@ -425,21 +428,22 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
return kvmppc_set_sregs_ivor(vcpu, sregs); return kvmppc_set_sregs_ivor(vcpu, sregs);
} }
int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_get_one_reg_e500(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
return r; return r;
} }
int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_set_one_reg_e500(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
return r; return r;
} }
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) static struct kvm_vcpu *kvmppc_core_vcpu_create_e500(struct kvm *kvm,
unsigned int id)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500; struct kvmppc_vcpu_e500 *vcpu_e500;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
@ -481,7 +485,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
return ERR_PTR(err); return ERR_PTR(err);
} }
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_free_e500(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@ -492,15 +496,32 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu_e500); kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
} }
int kvmppc_core_init_vm(struct kvm *kvm) static int kvmppc_core_init_vm_e500(struct kvm *kvm)
{ {
return 0; return 0;
} }
void kvmppc_core_destroy_vm(struct kvm *kvm) static void kvmppc_core_destroy_vm_e500(struct kvm *kvm)
{ {
} }
static struct kvmppc_ops kvm_ops_e500 = {
.get_sregs = kvmppc_core_get_sregs_e500,
.set_sregs = kvmppc_core_set_sregs_e500,
.get_one_reg = kvmppc_get_one_reg_e500,
.set_one_reg = kvmppc_set_one_reg_e500,
.vcpu_load = kvmppc_core_vcpu_load_e500,
.vcpu_put = kvmppc_core_vcpu_put_e500,
.vcpu_create = kvmppc_core_vcpu_create_e500,
.vcpu_free = kvmppc_core_vcpu_free_e500,
.mmu_destroy = kvmppc_mmu_destroy_e500,
.init_vm = kvmppc_core_init_vm_e500,
.destroy_vm = kvmppc_core_destroy_vm_e500,
.emulate_op = kvmppc_core_emulate_op_e500,
.emulate_mtspr = kvmppc_core_emulate_mtspr_e500,
.emulate_mfspr = kvmppc_core_emulate_mfspr_e500,
};
static int __init kvmppc_e500_init(void) static int __init kvmppc_e500_init(void)
{ {
int r, i; int r, i;
@ -512,11 +533,11 @@ static int __init kvmppc_e500_init(void)
r = kvmppc_core_check_processor_compat(); r = kvmppc_core_check_processor_compat();
if (r) if (r)
return r; goto err_out;
r = kvmppc_booke_init(); r = kvmppc_booke_init();
if (r) if (r)
return r; goto err_out;
/* copy extra E500 exception handlers */ /* copy extra E500 exception handlers */
ivor[0] = mfspr(SPRN_IVOR32); ivor[0] = mfspr(SPRN_IVOR32);
@ -534,11 +555,19 @@ static int __init kvmppc_e500_init(void)
flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers + flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
ivor[max_ivor] + handler_len); ivor[max_ivor] + handler_len);
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
if (r)
goto err_out;
kvm_ops_e500.owner = THIS_MODULE;
kvmppc_pr_ops = &kvm_ops_e500;
err_out:
return r;
} }
static void __exit kvmppc_e500_exit(void) static void __exit kvmppc_e500_exit(void)
{ {
kvmppc_pr_ops = NULL;
kvmppc_booke_exit(); kvmppc_booke_exit();
} }

View file

@ -117,7 +117,7 @@ static inline struct kvmppc_vcpu_e500 *to_e500(struct kvm_vcpu *vcpu)
#define E500_TLB_USER_PERM_MASK (MAS3_UX|MAS3_UR|MAS3_UW) #define E500_TLB_USER_PERM_MASK (MAS3_UX|MAS3_UR|MAS3_UW)
#define E500_TLB_SUPER_PERM_MASK (MAS3_SX|MAS3_SR|MAS3_SW) #define E500_TLB_SUPER_PERM_MASK (MAS3_SX|MAS3_SR|MAS3_SW)
#define MAS2_ATTRIB_MASK \ #define MAS2_ATTRIB_MASK \
(MAS2_X0 | MAS2_X1) (MAS2_X0 | MAS2_X1 | MAS2_E | MAS2_G)
#define MAS3_ATTRIB_MASK \ #define MAS3_ATTRIB_MASK \
(MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3 \ (MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3 \
| E500_TLB_USER_PERM_MASK | E500_TLB_SUPER_PERM_MASK) | E500_TLB_USER_PERM_MASK | E500_TLB_SUPER_PERM_MASK)

View file

@ -26,6 +26,7 @@
#define XOP_TLBRE 946 #define XOP_TLBRE 946
#define XOP_TLBWE 978 #define XOP_TLBWE 978
#define XOP_TLBILX 18 #define XOP_TLBILX 18
#define XOP_EHPRIV 270
#ifdef CONFIG_KVM_E500MC #ifdef CONFIG_KVM_E500MC
static int dbell2prio(ulong param) static int dbell2prio(ulong param)
@ -82,8 +83,28 @@ static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
} }
#endif #endif
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance) unsigned int inst, int *advance)
{
int emulated = EMULATE_DONE;
switch (get_oc(inst)) {
case EHPRIV_OC_DEBUG:
run->exit_reason = KVM_EXIT_DEBUG;
run->debug.arch.address = vcpu->arch.pc;
run->debug.arch.status = 0;
kvmppc_account_exit(vcpu, DEBUG_EXITS);
emulated = EMULATE_EXIT_USER;
*advance = 0;
break;
default:
emulated = EMULATE_FAIL;
}
return emulated;
}
int kvmppc_core_emulate_op_e500(struct kvm_run *run, struct kvm_vcpu *vcpu,
unsigned int inst, int *advance)
{ {
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
int ra = get_ra(inst); int ra = get_ra(inst);
@ -130,6 +151,11 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
emulated = kvmppc_e500_emul_tlbivax(vcpu, ea); emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
break; break;
case XOP_EHPRIV:
emulated = kvmppc_e500_emul_ehpriv(run, vcpu, inst,
advance);
break;
default: default:
emulated = EMULATE_FAIL; emulated = EMULATE_FAIL;
} }
@ -146,7 +172,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
return emulated; return emulated;
} }
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;
@ -237,7 +263,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
return emulated; return emulated;
} }
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
int emulated = EMULATE_DONE; int emulated = EMULATE_DONE;

View file

@ -32,7 +32,7 @@
#include <asm/kvm_ppc.h> #include <asm/kvm_ppc.h>
#include "e500.h" #include "e500.h"
#include "trace.h" #include "trace_booke.h"
#include "timing.h" #include "timing.h"
#include "e500_mmu_host.h" #include "e500_mmu_host.h"
@ -536,7 +536,7 @@ gpa_t kvmppc_mmu_xlate(struct kvm_vcpu *vcpu, unsigned int index,
return get_tlb_raddr(gtlbe) | (eaddr & pgmask); return get_tlb_raddr(gtlbe) | (eaddr & pgmask);
} }
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) void kvmppc_mmu_destroy_e500(struct kvm_vcpu *vcpu)
{ {
} }

View file

@ -32,10 +32,11 @@
#include <asm/kvm_ppc.h> #include <asm/kvm_ppc.h>
#include "e500.h" #include "e500.h"
#include "trace.h"
#include "timing.h" #include "timing.h"
#include "e500_mmu_host.h" #include "e500_mmu_host.h"
#include "trace_booke.h"
#define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1) #define to_htlb1_esel(esel) (host_tlb_params[1].entries - (esel) - 1)
static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM]; static struct kvmppc_e500_tlb_params host_tlb_params[E500_TLB_NUM];
@ -253,6 +254,9 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
ref->pfn = pfn; ref->pfn = pfn;
ref->flags |= E500_TLB_VALID; ref->flags |= E500_TLB_VALID;
/* Mark the page accessed */
kvm_set_pfn_accessed(pfn);
if (tlbe_is_writable(gtlbe)) if (tlbe_is_writable(gtlbe))
kvm_set_pfn_dirty(pfn); kvm_set_pfn_dirty(pfn);
} }

View file

@ -110,7 +110,7 @@ void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr)
static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu); static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu);
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@ -147,7 +147,7 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvmppc_load_guest_fp(vcpu); kvmppc_load_guest_fp(vcpu);
} }
void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu)
{ {
vcpu->arch.eplc = mfspr(SPRN_EPLC); vcpu->arch.eplc = mfspr(SPRN_EPLC);
vcpu->arch.epsc = mfspr(SPRN_EPSC); vcpu->arch.epsc = mfspr(SPRN_EPSC);
@ -204,7 +204,8 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_get_sregs_e500mc(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@ -224,10 +225,11 @@ void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
sregs->u.e.ivor_high[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]; sregs->u.e.ivor_high[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL];
sregs->u.e.ivor_high[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]; sregs->u.e.ivor_high[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT];
kvmppc_get_sregs_ivor(vcpu, sregs); return kvmppc_get_sregs_ivor(vcpu, sregs);
} }
int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) static int kvmppc_core_set_sregs_e500mc(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
int ret; int ret;
@ -260,21 +262,22 @@ int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
return kvmppc_set_sregs_ivor(vcpu, sregs); return kvmppc_set_sregs_ivor(vcpu, sregs);
} }
int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_get_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val);
return r; return r;
} }
int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, static int kvmppc_set_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id,
union kvmppc_one_reg *val) union kvmppc_one_reg *val)
{ {
int r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val); int r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val);
return r; return r;
} }
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) static struct kvm_vcpu *kvmppc_core_vcpu_create_e500mc(struct kvm *kvm,
unsigned int id)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500; struct kvmppc_vcpu_e500 *vcpu_e500;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
@ -315,7 +318,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
return ERR_PTR(err); return ERR_PTR(err);
} }
void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) static void kvmppc_core_vcpu_free_e500mc(struct kvm_vcpu *vcpu)
{ {
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@ -325,7 +328,7 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kmem_cache_free(kvm_vcpu_cache, vcpu_e500); kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
} }
int kvmppc_core_init_vm(struct kvm *kvm) static int kvmppc_core_init_vm_e500mc(struct kvm *kvm)
{ {
int lpid; int lpid;
@ -337,27 +340,52 @@ int kvmppc_core_init_vm(struct kvm *kvm)
return 0; return 0;
} }
void kvmppc_core_destroy_vm(struct kvm *kvm) static void kvmppc_core_destroy_vm_e500mc(struct kvm *kvm)
{ {
kvmppc_free_lpid(kvm->arch.lpid); kvmppc_free_lpid(kvm->arch.lpid);
} }
static struct kvmppc_ops kvm_ops_e500mc = {
.get_sregs = kvmppc_core_get_sregs_e500mc,
.set_sregs = kvmppc_core_set_sregs_e500mc,
.get_one_reg = kvmppc_get_one_reg_e500mc,
.set_one_reg = kvmppc_set_one_reg_e500mc,
.vcpu_load = kvmppc_core_vcpu_load_e500mc,
.vcpu_put = kvmppc_core_vcpu_put_e500mc,
.vcpu_create = kvmppc_core_vcpu_create_e500mc,
.vcpu_free = kvmppc_core_vcpu_free_e500mc,
.mmu_destroy = kvmppc_mmu_destroy_e500,
.init_vm = kvmppc_core_init_vm_e500mc,
.destroy_vm = kvmppc_core_destroy_vm_e500mc,
.emulate_op = kvmppc_core_emulate_op_e500,
.emulate_mtspr = kvmppc_core_emulate_mtspr_e500,
.emulate_mfspr = kvmppc_core_emulate_mfspr_e500,
};
static int __init kvmppc_e500mc_init(void) static int __init kvmppc_e500mc_init(void)
{ {
int r; int r;
r = kvmppc_booke_init(); r = kvmppc_booke_init();
if (r) if (r)
return r; goto err_out;
kvmppc_init_lpid(64); kvmppc_init_lpid(64);
kvmppc_claim_lpid(0); /* host */ kvmppc_claim_lpid(0); /* host */
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
if (r)
goto err_out;
kvm_ops_e500mc.owner = THIS_MODULE;
kvmppc_pr_ops = &kvm_ops_e500mc;
err_out:
return r;
} }
static void __exit kvmppc_e500mc_exit(void) static void __exit kvmppc_e500mc_exit(void)
{ {
kvmppc_pr_ops = NULL;
kvmppc_booke_exit(); kvmppc_booke_exit();
} }

View file

@ -130,8 +130,8 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
case SPRN_PIR: break; case SPRN_PIR: break;
default: default:
emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, emulated = vcpu->kvm->arch.kvm_ops->emulate_mtspr(vcpu, sprn,
spr_val); spr_val);
if (emulated == EMULATE_FAIL) if (emulated == EMULATE_FAIL)
printk(KERN_INFO "mtspr: unknown spr " printk(KERN_INFO "mtspr: unknown spr "
"0x%x\n", sprn); "0x%x\n", sprn);
@ -191,8 +191,8 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
spr_val = kvmppc_get_dec(vcpu, get_tb()); spr_val = kvmppc_get_dec(vcpu, get_tb());
break; break;
default: default:
emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, emulated = vcpu->kvm->arch.kvm_ops->emulate_mfspr(vcpu, sprn,
&spr_val); &spr_val);
if (unlikely(emulated == EMULATE_FAIL)) { if (unlikely(emulated == EMULATE_FAIL)) {
printk(KERN_INFO "mfspr: unknown spr " printk(KERN_INFO "mfspr: unknown spr "
"0x%x\n", sprn); "0x%x\n", sprn);
@ -464,7 +464,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
} }
if (emulated == EMULATE_FAIL) { if (emulated == EMULATE_FAIL) {
emulated = kvmppc_core_emulate_op(run, vcpu, inst, &advance); emulated = vcpu->kvm->arch.kvm_ops->emulate_op(run, vcpu, inst,
&advance);
if (emulated == EMULATE_AGAIN) { if (emulated == EMULATE_AGAIN) {
advance = 0; advance = 0;
} else if (emulated == EMULATE_FAIL) { } else if (emulated == EMULATE_FAIL) {
@ -483,3 +484,4 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
return emulated; return emulated;
} }
EXPORT_SYMBOL_GPL(kvmppc_emulate_instruction);

View file

@ -26,6 +26,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/module.h>
#include <asm/cputable.h> #include <asm/cputable.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/kvm_ppc.h> #include <asm/kvm_ppc.h>
@ -39,6 +40,12 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "trace.h" #include "trace.h"
struct kvmppc_ops *kvmppc_hv_ops;
EXPORT_SYMBOL_GPL(kvmppc_hv_ops);
struct kvmppc_ops *kvmppc_pr_ops;
EXPORT_SYMBOL_GPL(kvmppc_pr_ops);
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{ {
return !!(v->arch.pending_exceptions) || return !!(v->arch.pending_exceptions) ||
@ -50,7 +57,6 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
return 1; return 1;
} }
#ifndef CONFIG_KVM_BOOK3S_64_HV
/* /*
* Common checks before entering the guest world. Call with interrupts * Common checks before entering the guest world. Call with interrupts
* disabled. * disabled.
@ -125,7 +131,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
return r; return r;
} }
#endif /* CONFIG_KVM_BOOK3S_64_HV */ EXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter);
int kvmppc_kvm_pv(struct kvm_vcpu *vcpu) int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
{ {
@ -179,6 +185,7 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
return r; return r;
} }
EXPORT_SYMBOL_GPL(kvmppc_kvm_pv);
int kvmppc_sanity_check(struct kvm_vcpu *vcpu) int kvmppc_sanity_check(struct kvm_vcpu *vcpu)
{ {
@ -192,11 +199,9 @@ int kvmppc_sanity_check(struct kvm_vcpu *vcpu)
if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled) if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled)
goto out; goto out;
#ifdef CONFIG_KVM_BOOK3S_64_HV
/* HV KVM can only do PAPR mode for now */ /* HV KVM can only do PAPR mode for now */
if (!vcpu->arch.papr_enabled) if (!vcpu->arch.papr_enabled && is_kvmppc_hv_enabled(vcpu->kvm))
goto out; goto out;
#endif
#ifdef CONFIG_KVM_BOOKE_HV #ifdef CONFIG_KVM_BOOKE_HV
if (!cpu_has_feature(CPU_FTR_EMB_HV)) if (!cpu_has_feature(CPU_FTR_EMB_HV))
@ -209,6 +214,7 @@ int kvmppc_sanity_check(struct kvm_vcpu *vcpu)
vcpu->arch.sane = r; vcpu->arch.sane = r;
return r ? 0 : -EINVAL; return r ? 0 : -EINVAL;
} }
EXPORT_SYMBOL_GPL(kvmppc_sanity_check);
int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
{ {
@ -243,6 +249,7 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
return r; return r;
} }
EXPORT_SYMBOL_GPL(kvmppc_emulate_mmio);
int kvm_arch_hardware_enable(void *garbage) int kvm_arch_hardware_enable(void *garbage)
{ {
@ -269,10 +276,35 @@ void kvm_arch_check_processor_compat(void *rtn)
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{ {
if (type) struct kvmppc_ops *kvm_ops = NULL;
return -EINVAL; /*
* if we have both HV and PR enabled, default is HV
*/
if (type == 0) {
if (kvmppc_hv_ops)
kvm_ops = kvmppc_hv_ops;
else
kvm_ops = kvmppc_pr_ops;
if (!kvm_ops)
goto err_out;
} else if (type == KVM_VM_PPC_HV) {
if (!kvmppc_hv_ops)
goto err_out;
kvm_ops = kvmppc_hv_ops;
} else if (type == KVM_VM_PPC_PR) {
if (!kvmppc_pr_ops)
goto err_out;
kvm_ops = kvmppc_pr_ops;
} else
goto err_out;
if (kvm_ops->owner && !try_module_get(kvm_ops->owner))
return -ENOENT;
kvm->arch.kvm_ops = kvm_ops;
return kvmppc_core_init_vm(kvm); return kvmppc_core_init_vm(kvm);
err_out:
return -EINVAL;
} }
void kvm_arch_destroy_vm(struct kvm *kvm) void kvm_arch_destroy_vm(struct kvm *kvm)
@ -292,6 +324,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvmppc_core_destroy_vm(kvm); kvmppc_core_destroy_vm(kvm);
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
/* drop the module reference */
module_put(kvm->arch.kvm_ops->owner);
} }
void kvm_arch_sync_events(struct kvm *kvm) void kvm_arch_sync_events(struct kvm *kvm)
@ -301,6 +336,10 @@ void kvm_arch_sync_events(struct kvm *kvm)
int kvm_dev_ioctl_check_extension(long ext) int kvm_dev_ioctl_check_extension(long ext)
{ {
int r; int r;
/* FIXME!!
* Should some of this be vm ioctl ? is it possible now ?
*/
int hv_enabled = kvmppc_hv_ops ? 1 : 0;
switch (ext) { switch (ext) {
#ifdef CONFIG_BOOKE #ifdef CONFIG_BOOKE
@ -320,22 +359,26 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_DEVICE_CTRL: case KVM_CAP_DEVICE_CTRL:
r = 1; r = 1;
break; break;
#ifndef CONFIG_KVM_BOOK3S_64_HV
case KVM_CAP_PPC_PAIRED_SINGLES: case KVM_CAP_PPC_PAIRED_SINGLES:
case KVM_CAP_PPC_OSI: case KVM_CAP_PPC_OSI:
case KVM_CAP_PPC_GET_PVINFO: case KVM_CAP_PPC_GET_PVINFO:
#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
case KVM_CAP_SW_TLB: case KVM_CAP_SW_TLB:
#endif #endif
#ifdef CONFIG_KVM_MPIC /* We support this only for PR */
case KVM_CAP_IRQ_MPIC: r = !hv_enabled;
#endif
r = 1;
break; break;
#ifdef CONFIG_KVM_MMIO
case KVM_CAP_COALESCED_MMIO: case KVM_CAP_COALESCED_MMIO:
r = KVM_COALESCED_MMIO_PAGE_OFFSET; r = KVM_COALESCED_MMIO_PAGE_OFFSET;
break; break;
#endif #endif
#ifdef CONFIG_KVM_MPIC
case KVM_CAP_IRQ_MPIC:
r = 1;
break;
#endif
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
case KVM_CAP_SPAPR_TCE: case KVM_CAP_SPAPR_TCE:
case KVM_CAP_PPC_ALLOC_HTAB: case KVM_CAP_PPC_ALLOC_HTAB:
@ -346,32 +389,37 @@ int kvm_dev_ioctl_check_extension(long ext)
r = 1; r = 1;
break; break;
#endif /* CONFIG_PPC_BOOK3S_64 */ #endif /* CONFIG_PPC_BOOK3S_64 */
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
case KVM_CAP_PPC_SMT: case KVM_CAP_PPC_SMT:
r = threads_per_core; if (hv_enabled)
r = threads_per_core;
else
r = 0;
break; break;
case KVM_CAP_PPC_RMA: case KVM_CAP_PPC_RMA:
r = 1; r = hv_enabled;
/* PPC970 requires an RMA */ /* PPC970 requires an RMA */
if (cpu_has_feature(CPU_FTR_ARCH_201)) if (r && cpu_has_feature(CPU_FTR_ARCH_201))
r = 2; r = 2;
break; break;
#endif #endif
case KVM_CAP_SYNC_MMU: case KVM_CAP_SYNC_MMU:
#ifdef CONFIG_KVM_BOOK3S_64_HV #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0; if (hv_enabled)
r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
else
r = 0;
#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) #elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
r = 1; r = 1;
#else #else
r = 0; r = 0;
break;
#endif #endif
#ifdef CONFIG_KVM_BOOK3S_64_HV break;
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
case KVM_CAP_PPC_HTAB_FD: case KVM_CAP_PPC_HTAB_FD:
r = 1; r = hv_enabled;
break; break;
#endif #endif
break;
case KVM_CAP_NR_VCPUS: case KVM_CAP_NR_VCPUS:
/* /*
* Recommending a number of CPUs is somewhat arbitrary; we * Recommending a number of CPUs is somewhat arbitrary; we
@ -379,11 +427,10 @@ int kvm_dev_ioctl_check_extension(long ext)
* will have secondary threads "offline"), and for other KVM * will have secondary threads "offline"), and for other KVM
* implementations just count online CPUs. * implementations just count online CPUs.
*/ */
#ifdef CONFIG_KVM_BOOK3S_64_HV if (hv_enabled)
r = num_present_cpus(); r = num_present_cpus();
#else else
r = num_online_cpus(); r = num_online_cpus();
#endif
break; break;
case KVM_CAP_MAX_VCPUS: case KVM_CAP_MAX_VCPUS:
r = KVM_MAX_VCPUS; r = KVM_MAX_VCPUS;
@ -407,15 +454,16 @@ long kvm_arch_dev_ioctl(struct file *filp,
return -EINVAL; return -EINVAL;
} }
void kvm_arch_free_memslot(struct kvm_memory_slot *free, void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free,
struct kvm_memory_slot *dont) struct kvm_memory_slot *dont)
{ {
kvmppc_core_free_memslot(free, dont); kvmppc_core_free_memslot(kvm, free, dont);
} }
int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages) int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
unsigned long npages)
{ {
return kvmppc_core_create_memslot(slot, npages); return kvmppc_core_create_memslot(kvm, slot, npages);
} }
void kvm_arch_memslots_updated(struct kvm *kvm) void kvm_arch_memslots_updated(struct kvm *kvm)
@ -659,6 +707,7 @@ int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
EXPORT_SYMBOL_GPL(kvmppc_handle_load);
/* Same as above, but sign extends */ /* Same as above, but sign extends */
int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu, int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
@ -720,6 +769,7 @@ int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
return EMULATE_DO_MMIO; return EMULATE_DO_MMIO;
} }
EXPORT_SYMBOL_GPL(kvmppc_handle_store);
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{ {
@ -1024,52 +1074,12 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce); r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce);
goto out; goto out;
} }
#endif /* CONFIG_PPC_BOOK3S_64 */
#ifdef CONFIG_KVM_BOOK3S_64_HV
case KVM_ALLOCATE_RMA: {
struct kvm_allocate_rma rma;
struct kvm *kvm = filp->private_data;
r = kvm_vm_ioctl_allocate_rma(kvm, &rma);
if (r >= 0 && copy_to_user(argp, &rma, sizeof(rma)))
r = -EFAULT;
break;
}
case KVM_PPC_ALLOCATE_HTAB: {
u32 htab_order;
r = -EFAULT;
if (get_user(htab_order, (u32 __user *)argp))
break;
r = kvmppc_alloc_reset_hpt(kvm, &htab_order);
if (r)
break;
r = -EFAULT;
if (put_user(htab_order, (u32 __user *)argp))
break;
r = 0;
break;
}
case KVM_PPC_GET_HTAB_FD: {
struct kvm_get_htab_fd ghf;
r = -EFAULT;
if (copy_from_user(&ghf, argp, sizeof(ghf)))
break;
r = kvm_vm_ioctl_get_htab_fd(kvm, &ghf);
break;
}
#endif /* CONFIG_KVM_BOOK3S_64_HV */
#ifdef CONFIG_PPC_BOOK3S_64
case KVM_PPC_GET_SMMU_INFO: { case KVM_PPC_GET_SMMU_INFO: {
struct kvm_ppc_smmu_info info; struct kvm_ppc_smmu_info info;
struct kvm *kvm = filp->private_data;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
r = kvm_vm_ioctl_get_smmu_info(kvm, &info); r = kvm->arch.kvm_ops->get_smmu_info(kvm, &info);
if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) if (r >= 0 && copy_to_user(argp, &info, sizeof(info)))
r = -EFAULT; r = -EFAULT;
break; break;
@ -1080,11 +1090,15 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_vm_ioctl_rtas_define_token(kvm, argp); r = kvm_vm_ioctl_rtas_define_token(kvm, argp);
break; break;
} }
#endif /* CONFIG_PPC_BOOK3S_64 */ default: {
struct kvm *kvm = filp->private_data;
r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
}
#else /* CONFIG_PPC_BOOK3S_64 */
default: default:
r = -ENOTTY; r = -ENOTTY;
#endif
} }
out: out:
return r; return r;
} }
@ -1106,22 +1120,26 @@ long kvmppc_alloc_lpid(void)
return lpid; return lpid;
} }
EXPORT_SYMBOL_GPL(kvmppc_alloc_lpid);
void kvmppc_claim_lpid(long lpid) void kvmppc_claim_lpid(long lpid)
{ {
set_bit(lpid, lpid_inuse); set_bit(lpid, lpid_inuse);
} }
EXPORT_SYMBOL_GPL(kvmppc_claim_lpid);
void kvmppc_free_lpid(long lpid) void kvmppc_free_lpid(long lpid)
{ {
clear_bit(lpid, lpid_inuse); clear_bit(lpid, lpid_inuse);
} }
EXPORT_SYMBOL_GPL(kvmppc_free_lpid);
void kvmppc_init_lpid(unsigned long nr_lpids_param) void kvmppc_init_lpid(unsigned long nr_lpids_param)
{ {
nr_lpids = min_t(unsigned long, KVMPPC_NR_LPIDS, nr_lpids_param); nr_lpids = min_t(unsigned long, KVMPPC_NR_LPIDS, nr_lpids_param);
memset(lpid_inuse, 0, sizeof(lpid_inuse)); memset(lpid_inuse, 0, sizeof(lpid_inuse));
} }
EXPORT_SYMBOL_GPL(kvmppc_init_lpid);
int kvm_arch_init(void *opaque) int kvm_arch_init(void *opaque)
{ {
@ -1130,4 +1148,5 @@ int kvm_arch_init(void *opaque)
void kvm_arch_exit(void) void kvm_arch_exit(void)
{ {
} }

View file

@ -31,126 +31,6 @@ TRACE_EVENT(kvm_ppc_instr,
__entry->inst, __entry->pc, __entry->emulate) __entry->inst, __entry->pc, __entry->emulate)
); );
#ifdef CONFIG_PPC_BOOK3S
#define kvm_trace_symbol_exit \
{0x100, "SYSTEM_RESET"}, \
{0x200, "MACHINE_CHECK"}, \
{0x300, "DATA_STORAGE"}, \
{0x380, "DATA_SEGMENT"}, \
{0x400, "INST_STORAGE"}, \
{0x480, "INST_SEGMENT"}, \
{0x500, "EXTERNAL"}, \
{0x501, "EXTERNAL_LEVEL"}, \
{0x502, "EXTERNAL_HV"}, \
{0x600, "ALIGNMENT"}, \
{0x700, "PROGRAM"}, \
{0x800, "FP_UNAVAIL"}, \
{0x900, "DECREMENTER"}, \
{0x980, "HV_DECREMENTER"}, \
{0xc00, "SYSCALL"}, \
{0xd00, "TRACE"}, \
{0xe00, "H_DATA_STORAGE"}, \
{0xe20, "H_INST_STORAGE"}, \
{0xe40, "H_EMUL_ASSIST"}, \
{0xf00, "PERFMON"}, \
{0xf20, "ALTIVEC"}, \
{0xf40, "VSX"}
#else
#define kvm_trace_symbol_exit \
{0, "CRITICAL"}, \
{1, "MACHINE_CHECK"}, \
{2, "DATA_STORAGE"}, \
{3, "INST_STORAGE"}, \
{4, "EXTERNAL"}, \
{5, "ALIGNMENT"}, \
{6, "PROGRAM"}, \
{7, "FP_UNAVAIL"}, \
{8, "SYSCALL"}, \
{9, "AP_UNAVAIL"}, \
{10, "DECREMENTER"}, \
{11, "FIT"}, \
{12, "WATCHDOG"}, \
{13, "DTLB_MISS"}, \
{14, "ITLB_MISS"}, \
{15, "DEBUG"}, \
{32, "SPE_UNAVAIL"}, \
{33, "SPE_FP_DATA"}, \
{34, "SPE_FP_ROUND"}, \
{35, "PERFORMANCE_MONITOR"}, \
{36, "DOORBELL"}, \
{37, "DOORBELL_CRITICAL"}, \
{38, "GUEST_DBELL"}, \
{39, "GUEST_DBELL_CRIT"}, \
{40, "HV_SYSCALL"}, \
{41, "HV_PRIV"}
#endif
TRACE_EVENT(kvm_exit,
TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
TP_ARGS(exit_nr, vcpu),
TP_STRUCT__entry(
__field( unsigned int, exit_nr )
__field( unsigned long, pc )
__field( unsigned long, msr )
__field( unsigned long, dar )
#ifdef CONFIG_KVM_BOOK3S_PR
__field( unsigned long, srr1 )
#endif
__field( unsigned long, last_inst )
),
TP_fast_assign(
#ifdef CONFIG_KVM_BOOK3S_PR
struct kvmppc_book3s_shadow_vcpu *svcpu;
#endif
__entry->exit_nr = exit_nr;
__entry->pc = kvmppc_get_pc(vcpu);
__entry->dar = kvmppc_get_fault_dar(vcpu);
__entry->msr = vcpu->arch.shared->msr;
#ifdef CONFIG_KVM_BOOK3S_PR
svcpu = svcpu_get(vcpu);
__entry->srr1 = svcpu->shadow_srr1;
svcpu_put(svcpu);
#endif
__entry->last_inst = vcpu->arch.last_inst;
),
TP_printk("exit=%s"
" | pc=0x%lx"
" | msr=0x%lx"
" | dar=0x%lx"
#ifdef CONFIG_KVM_BOOK3S_PR
" | srr1=0x%lx"
#endif
" | last_inst=0x%lx"
,
__print_symbolic(__entry->exit_nr, kvm_trace_symbol_exit),
__entry->pc,
__entry->msr,
__entry->dar,
#ifdef CONFIG_KVM_BOOK3S_PR
__entry->srr1,
#endif
__entry->last_inst
)
);
TRACE_EVENT(kvm_unmap_hva,
TP_PROTO(unsigned long hva),
TP_ARGS(hva),
TP_STRUCT__entry(
__field( unsigned long, hva )
),
TP_fast_assign(
__entry->hva = hva;
),
TP_printk("unmap hva 0x%lx\n", __entry->hva)
);
TRACE_EVENT(kvm_stlb_inval, TRACE_EVENT(kvm_stlb_inval,
TP_PROTO(unsigned int stlb_index), TP_PROTO(unsigned int stlb_index),
TP_ARGS(stlb_index), TP_ARGS(stlb_index),
@ -236,315 +116,6 @@ TRACE_EVENT(kvm_check_requests,
__entry->cpu_nr, __entry->requests) __entry->cpu_nr, __entry->requests)
); );
/*************************************************************************
* Book3S trace points *
*************************************************************************/
#ifdef CONFIG_KVM_BOOK3S_PR
TRACE_EVENT(kvm_book3s_reenter,
TP_PROTO(int r, struct kvm_vcpu *vcpu),
TP_ARGS(r, vcpu),
TP_STRUCT__entry(
__field( unsigned int, r )
__field( unsigned long, pc )
),
TP_fast_assign(
__entry->r = r;
__entry->pc = kvmppc_get_pc(vcpu);
),
TP_printk("reentry r=%d | pc=0x%lx", __entry->r, __entry->pc)
);
#ifdef CONFIG_PPC_BOOK3S_64
TRACE_EVENT(kvm_book3s_64_mmu_map,
TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
struct kvmppc_pte *orig_pte),
TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
TP_STRUCT__entry(
__field( unsigned char, flag_w )
__field( unsigned char, flag_x )
__field( unsigned long, eaddr )
__field( unsigned long, hpteg )
__field( unsigned long, va )
__field( unsigned long long, vpage )
__field( unsigned long, hpaddr )
),
TP_fast_assign(
__entry->flag_w = ((rflags & HPTE_R_PP) == 3) ? '-' : 'w';
__entry->flag_x = (rflags & HPTE_R_N) ? '-' : 'x';
__entry->eaddr = orig_pte->eaddr;
__entry->hpteg = hpteg;
__entry->va = va;
__entry->vpage = orig_pte->vpage;
__entry->hpaddr = hpaddr;
),
TP_printk("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx",
__entry->flag_w, __entry->flag_x, __entry->eaddr,
__entry->hpteg, __entry->va, __entry->vpage, __entry->hpaddr)
);
#endif /* CONFIG_PPC_BOOK3S_64 */
TRACE_EVENT(kvm_book3s_mmu_map,
TP_PROTO(struct hpte_cache *pte),
TP_ARGS(pte),
TP_STRUCT__entry(
__field( u64, host_vpn )
__field( u64, pfn )
__field( ulong, eaddr )
__field( u64, vpage )
__field( ulong, raddr )
__field( int, flags )
),
TP_fast_assign(
__entry->host_vpn = pte->host_vpn;
__entry->pfn = pte->pfn;
__entry->eaddr = pte->pte.eaddr;
__entry->vpage = pte->pte.vpage;
__entry->raddr = pte->pte.raddr;
__entry->flags = (pte->pte.may_read ? 0x4 : 0) |
(pte->pte.may_write ? 0x2 : 0) |
(pte->pte.may_execute ? 0x1 : 0);
),
TP_printk("Map: hvpn=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
__entry->host_vpn, __entry->pfn, __entry->eaddr,
__entry->vpage, __entry->raddr, __entry->flags)
);
TRACE_EVENT(kvm_book3s_mmu_invalidate,
TP_PROTO(struct hpte_cache *pte),
TP_ARGS(pte),
TP_STRUCT__entry(
__field( u64, host_vpn )
__field( u64, pfn )
__field( ulong, eaddr )
__field( u64, vpage )
__field( ulong, raddr )
__field( int, flags )
),
TP_fast_assign(
__entry->host_vpn = pte->host_vpn;
__entry->pfn = pte->pfn;
__entry->eaddr = pte->pte.eaddr;
__entry->vpage = pte->pte.vpage;
__entry->raddr = pte->pte.raddr;
__entry->flags = (pte->pte.may_read ? 0x4 : 0) |
(pte->pte.may_write ? 0x2 : 0) |
(pte->pte.may_execute ? 0x1 : 0);
),
TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
__entry->host_vpn, __entry->pfn, __entry->eaddr,
__entry->vpage, __entry->raddr, __entry->flags)
);
TRACE_EVENT(kvm_book3s_mmu_flush,
TP_PROTO(const char *type, struct kvm_vcpu *vcpu, unsigned long long p1,
unsigned long long p2),
TP_ARGS(type, vcpu, p1, p2),
TP_STRUCT__entry(
__field( int, count )
__field( unsigned long long, p1 )
__field( unsigned long long, p2 )
__field( const char *, type )
),
TP_fast_assign(
__entry->count = to_book3s(vcpu)->hpte_cache_count;
__entry->p1 = p1;
__entry->p2 = p2;
__entry->type = type;
),
TP_printk("Flush %d %sPTEs: %llx - %llx",
__entry->count, __entry->type, __entry->p1, __entry->p2)
);
TRACE_EVENT(kvm_book3s_slb_found,
TP_PROTO(unsigned long long gvsid, unsigned long long hvsid),
TP_ARGS(gvsid, hvsid),
TP_STRUCT__entry(
__field( unsigned long long, gvsid )
__field( unsigned long long, hvsid )
),
TP_fast_assign(
__entry->gvsid = gvsid;
__entry->hvsid = hvsid;
),
TP_printk("%llx -> %llx", __entry->gvsid, __entry->hvsid)
);
TRACE_EVENT(kvm_book3s_slb_fail,
TP_PROTO(u16 sid_map_mask, unsigned long long gvsid),
TP_ARGS(sid_map_mask, gvsid),
TP_STRUCT__entry(
__field( unsigned short, sid_map_mask )
__field( unsigned long long, gvsid )
),
TP_fast_assign(
__entry->sid_map_mask = sid_map_mask;
__entry->gvsid = gvsid;
),
TP_printk("%x/%x: %llx", __entry->sid_map_mask,
SID_MAP_MASK - __entry->sid_map_mask, __entry->gvsid)
);
TRACE_EVENT(kvm_book3s_slb_map,
TP_PROTO(u16 sid_map_mask, unsigned long long gvsid,
unsigned long long hvsid),
TP_ARGS(sid_map_mask, gvsid, hvsid),
TP_STRUCT__entry(
__field( unsigned short, sid_map_mask )
__field( unsigned long long, guest_vsid )
__field( unsigned long long, host_vsid )
),
TP_fast_assign(
__entry->sid_map_mask = sid_map_mask;
__entry->guest_vsid = gvsid;
__entry->host_vsid = hvsid;
),
TP_printk("%x: %llx -> %llx", __entry->sid_map_mask,
__entry->guest_vsid, __entry->host_vsid)
);
TRACE_EVENT(kvm_book3s_slbmte,
TP_PROTO(u64 slb_vsid, u64 slb_esid),
TP_ARGS(slb_vsid, slb_esid),
TP_STRUCT__entry(
__field( u64, slb_vsid )
__field( u64, slb_esid )
),
TP_fast_assign(
__entry->slb_vsid = slb_vsid;
__entry->slb_esid = slb_esid;
),
TP_printk("%llx, %llx", __entry->slb_vsid, __entry->slb_esid)
);
#endif /* CONFIG_PPC_BOOK3S */
/*************************************************************************
* Book3E trace points *
*************************************************************************/
#ifdef CONFIG_BOOKE
TRACE_EVENT(kvm_booke206_stlb_write,
TP_PROTO(__u32 mas0, __u32 mas8, __u32 mas1, __u64 mas2, __u64 mas7_3),
TP_ARGS(mas0, mas8, mas1, mas2, mas7_3),
TP_STRUCT__entry(
__field( __u32, mas0 )
__field( __u32, mas8 )
__field( __u32, mas1 )
__field( __u64, mas2 )
__field( __u64, mas7_3 )
),
TP_fast_assign(
__entry->mas0 = mas0;
__entry->mas8 = mas8;
__entry->mas1 = mas1;
__entry->mas2 = mas2;
__entry->mas7_3 = mas7_3;
),
TP_printk("mas0=%x mas8=%x mas1=%x mas2=%llx mas7_3=%llx",
__entry->mas0, __entry->mas8, __entry->mas1,
__entry->mas2, __entry->mas7_3)
);
TRACE_EVENT(kvm_booke206_gtlb_write,
TP_PROTO(__u32 mas0, __u32 mas1, __u64 mas2, __u64 mas7_3),
TP_ARGS(mas0, mas1, mas2, mas7_3),
TP_STRUCT__entry(
__field( __u32, mas0 )
__field( __u32, mas1 )
__field( __u64, mas2 )
__field( __u64, mas7_3 )
),
TP_fast_assign(
__entry->mas0 = mas0;
__entry->mas1 = mas1;
__entry->mas2 = mas2;
__entry->mas7_3 = mas7_3;
),
TP_printk("mas0=%x mas1=%x mas2=%llx mas7_3=%llx",
__entry->mas0, __entry->mas1,
__entry->mas2, __entry->mas7_3)
);
TRACE_EVENT(kvm_booke206_ref_release,
TP_PROTO(__u64 pfn, __u32 flags),
TP_ARGS(pfn, flags),
TP_STRUCT__entry(
__field( __u64, pfn )
__field( __u32, flags )
),
TP_fast_assign(
__entry->pfn = pfn;
__entry->flags = flags;
),
TP_printk("pfn=%llx flags=%x",
__entry->pfn, __entry->flags)
);
TRACE_EVENT(kvm_booke_queue_irqprio,
TP_PROTO(struct kvm_vcpu *vcpu, unsigned int priority),
TP_ARGS(vcpu, priority),
TP_STRUCT__entry(
__field( __u32, cpu_nr )
__field( __u32, priority )
__field( unsigned long, pending )
),
TP_fast_assign(
__entry->cpu_nr = vcpu->vcpu_id;
__entry->priority = priority;
__entry->pending = vcpu->arch.pending_exceptions;
),
TP_printk("vcpu=%x prio=%x pending=%lx",
__entry->cpu_nr, __entry->priority, __entry->pending)
);
#endif
#endif /* _TRACE_KVM_H */ #endif /* _TRACE_KVM_H */
/* This part must be outside protection */ /* This part must be outside protection */

View file

@ -0,0 +1,177 @@
#if !defined(_TRACE_KVM_BOOKE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_KVM_BOOKE_H
#include <linux/tracepoint.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM kvm_booke
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_booke
#define kvm_trace_symbol_exit \
{0, "CRITICAL"}, \
{1, "MACHINE_CHECK"}, \
{2, "DATA_STORAGE"}, \
{3, "INST_STORAGE"}, \
{4, "EXTERNAL"}, \
{5, "ALIGNMENT"}, \
{6, "PROGRAM"}, \
{7, "FP_UNAVAIL"}, \
{8, "SYSCALL"}, \
{9, "AP_UNAVAIL"}, \
{10, "DECREMENTER"}, \
{11, "FIT"}, \
{12, "WATCHDOG"}, \
{13, "DTLB_MISS"}, \
{14, "ITLB_MISS"}, \
{15, "DEBUG"}, \
{32, "SPE_UNAVAIL"}, \
{33, "SPE_FP_DATA"}, \
{34, "SPE_FP_ROUND"}, \
{35, "PERFORMANCE_MONITOR"}, \
{36, "DOORBELL"}, \
{37, "DOORBELL_CRITICAL"}, \
{38, "GUEST_DBELL"}, \
{39, "GUEST_DBELL_CRIT"}, \
{40, "HV_SYSCALL"}, \
{41, "HV_PRIV"}
TRACE_EVENT(kvm_exit,
TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
TP_ARGS(exit_nr, vcpu),
TP_STRUCT__entry(
__field( unsigned int, exit_nr )
__field( unsigned long, pc )
__field( unsigned long, msr )
__field( unsigned long, dar )
__field( unsigned long, last_inst )
),
TP_fast_assign(
__entry->exit_nr = exit_nr;
__entry->pc = kvmppc_get_pc(vcpu);
__entry->dar = kvmppc_get_fault_dar(vcpu);
__entry->msr = vcpu->arch.shared->msr;
__entry->last_inst = vcpu->arch.last_inst;
),
TP_printk("exit=%s"
" | pc=0x%lx"
" | msr=0x%lx"
" | dar=0x%lx"
" | last_inst=0x%lx"
,
__print_symbolic(__entry->exit_nr, kvm_trace_symbol_exit),
__entry->pc,
__entry->msr,
__entry->dar,
__entry->last_inst
)
);
TRACE_EVENT(kvm_unmap_hva,
TP_PROTO(unsigned long hva),
TP_ARGS(hva),
TP_STRUCT__entry(
__field( unsigned long, hva )
),
TP_fast_assign(
__entry->hva = hva;
),
TP_printk("unmap hva 0x%lx\n", __entry->hva)
);
TRACE_EVENT(kvm_booke206_stlb_write,
TP_PROTO(__u32 mas0, __u32 mas8, __u32 mas1, __u64 mas2, __u64 mas7_3),
TP_ARGS(mas0, mas8, mas1, mas2, mas7_3),
TP_STRUCT__entry(
__field( __u32, mas0 )
__field( __u32, mas8 )
__field( __u32, mas1 )
__field( __u64, mas2 )
__field( __u64, mas7_3 )
),
TP_fast_assign(
__entry->mas0 = mas0;
__entry->mas8 = mas8;
__entry->mas1 = mas1;
__entry->mas2 = mas2;
__entry->mas7_3 = mas7_3;
),
TP_printk("mas0=%x mas8=%x mas1=%x mas2=%llx mas7_3=%llx",
__entry->mas0, __entry->mas8, __entry->mas1,
__entry->mas2, __entry->mas7_3)
);
TRACE_EVENT(kvm_booke206_gtlb_write,
TP_PROTO(__u32 mas0, __u32 mas1, __u64 mas2, __u64 mas7_3),
TP_ARGS(mas0, mas1, mas2, mas7_3),
TP_STRUCT__entry(
__field( __u32, mas0 )
__field( __u32, mas1 )
__field( __u64, mas2 )
__field( __u64, mas7_3 )
),
TP_fast_assign(
__entry->mas0 = mas0;
__entry->mas1 = mas1;
__entry->mas2 = mas2;
__entry->mas7_3 = mas7_3;
),
TP_printk("mas0=%x mas1=%x mas2=%llx mas7_3=%llx",
__entry->mas0, __entry->mas1,
__entry->mas2, __entry->mas7_3)
);
TRACE_EVENT(kvm_booke206_ref_release,
TP_PROTO(__u64 pfn, __u32 flags),
TP_ARGS(pfn, flags),
TP_STRUCT__entry(
__field( __u64, pfn )
__field( __u32, flags )
),
TP_fast_assign(
__entry->pfn = pfn;
__entry->flags = flags;
),
TP_printk("pfn=%llx flags=%x",
__entry->pfn, __entry->flags)
);
TRACE_EVENT(kvm_booke_queue_irqprio,
TP_PROTO(struct kvm_vcpu *vcpu, unsigned int priority),
TP_ARGS(vcpu, priority),
TP_STRUCT__entry(
__field( __u32, cpu_nr )
__field( __u32, priority )
__field( unsigned long, pending )
),
TP_fast_assign(
__entry->cpu_nr = vcpu->vcpu_id;
__entry->priority = priority;
__entry->pending = vcpu->arch.pending_exceptions;
),
TP_printk("vcpu=%x prio=%x pending=%lx",
__entry->cpu_nr, __entry->priority, __entry->pending)
);
#endif
/* This part must be outside protection */
#include <trace/define_trace.h>

297
arch/powerpc/kvm/trace_pr.h Normal file
View file

@ -0,0 +1,297 @@
#if !defined(_TRACE_KVM_PR_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_KVM_PR_H
#include <linux/tracepoint.h>
#undef TRACE_SYSTEM
#define TRACE_SYSTEM kvm_pr
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE trace_pr
#define kvm_trace_symbol_exit \
{0x100, "SYSTEM_RESET"}, \
{0x200, "MACHINE_CHECK"}, \
{0x300, "DATA_STORAGE"}, \
{0x380, "DATA_SEGMENT"}, \
{0x400, "INST_STORAGE"}, \
{0x480, "INST_SEGMENT"}, \
{0x500, "EXTERNAL"}, \
{0x501, "EXTERNAL_LEVEL"}, \
{0x502, "EXTERNAL_HV"}, \
{0x600, "ALIGNMENT"}, \
{0x700, "PROGRAM"}, \
{0x800, "FP_UNAVAIL"}, \
{0x900, "DECREMENTER"}, \
{0x980, "HV_DECREMENTER"}, \
{0xc00, "SYSCALL"}, \
{0xd00, "TRACE"}, \
{0xe00, "H_DATA_STORAGE"}, \
{0xe20, "H_INST_STORAGE"}, \
{0xe40, "H_EMUL_ASSIST"}, \
{0xf00, "PERFMON"}, \
{0xf20, "ALTIVEC"}, \
{0xf40, "VSX"}
TRACE_EVENT(kvm_book3s_reenter,
TP_PROTO(int r, struct kvm_vcpu *vcpu),
TP_ARGS(r, vcpu),
TP_STRUCT__entry(
__field( unsigned int, r )
__field( unsigned long, pc )
),
TP_fast_assign(
__entry->r = r;
__entry->pc = kvmppc_get_pc(vcpu);
),
TP_printk("reentry r=%d | pc=0x%lx", __entry->r, __entry->pc)
);
#ifdef CONFIG_PPC_BOOK3S_64
TRACE_EVENT(kvm_book3s_64_mmu_map,
TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
struct kvmppc_pte *orig_pte),
TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
TP_STRUCT__entry(
__field( unsigned char, flag_w )
__field( unsigned char, flag_x )
__field( unsigned long, eaddr )
__field( unsigned long, hpteg )
__field( unsigned long, va )
__field( unsigned long long, vpage )
__field( unsigned long, hpaddr )
),
TP_fast_assign(
__entry->flag_w = ((rflags & HPTE_R_PP) == 3) ? '-' : 'w';
__entry->flag_x = (rflags & HPTE_R_N) ? '-' : 'x';
__entry->eaddr = orig_pte->eaddr;
__entry->hpteg = hpteg;
__entry->va = va;
__entry->vpage = orig_pte->vpage;
__entry->hpaddr = hpaddr;
),
TP_printk("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx",
__entry->flag_w, __entry->flag_x, __entry->eaddr,
__entry->hpteg, __entry->va, __entry->vpage, __entry->hpaddr)
);
#endif /* CONFIG_PPC_BOOK3S_64 */
TRACE_EVENT(kvm_book3s_mmu_map,
TP_PROTO(struct hpte_cache *pte),
TP_ARGS(pte),
TP_STRUCT__entry(
__field( u64, host_vpn )
__field( u64, pfn )
__field( ulong, eaddr )
__field( u64, vpage )
__field( ulong, raddr )
__field( int, flags )
),
TP_fast_assign(
__entry->host_vpn = pte->host_vpn;
__entry->pfn = pte->pfn;
__entry->eaddr = pte->pte.eaddr;
__entry->vpage = pte->pte.vpage;
__entry->raddr = pte->pte.raddr;
__entry->flags = (pte->pte.may_read ? 0x4 : 0) |
(pte->pte.may_write ? 0x2 : 0) |
(pte->pte.may_execute ? 0x1 : 0);
),
TP_printk("Map: hvpn=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
__entry->host_vpn, __entry->pfn, __entry->eaddr,
__entry->vpage, __entry->raddr, __entry->flags)
);
TRACE_EVENT(kvm_book3s_mmu_invalidate,
TP_PROTO(struct hpte_cache *pte),
TP_ARGS(pte),
TP_STRUCT__entry(
__field( u64, host_vpn )
__field( u64, pfn )
__field( ulong, eaddr )
__field( u64, vpage )
__field( ulong, raddr )
__field( int, flags )
),
TP_fast_assign(
__entry->host_vpn = pte->host_vpn;
__entry->pfn = pte->pfn;
__entry->eaddr = pte->pte.eaddr;
__entry->vpage = pte->pte.vpage;
__entry->raddr = pte->pte.raddr;
__entry->flags = (pte->pte.may_read ? 0x4 : 0) |
(pte->pte.may_write ? 0x2 : 0) |
(pte->pte.may_execute ? 0x1 : 0);
),
TP_printk("Flush: hva=%llx pfn=%llx ea=%lx vp=%llx ra=%lx [%x]",
__entry->host_vpn, __entry->pfn, __entry->eaddr,
__entry->vpage, __entry->raddr, __entry->flags)
);
TRACE_EVENT(kvm_book3s_mmu_flush,
TP_PROTO(const char *type, struct kvm_vcpu *vcpu, unsigned long long p1,
unsigned long long p2),
TP_ARGS(type, vcpu, p1, p2),
TP_STRUCT__entry(
__field( int, count )
__field( unsigned long long, p1 )
__field( unsigned long long, p2 )
__field( const char *, type )
),
TP_fast_assign(
__entry->count = to_book3s(vcpu)->hpte_cache_count;
__entry->p1 = p1;
__entry->p2 = p2;
__entry->type = type;
),
TP_printk("Flush %d %sPTEs: %llx - %llx",
__entry->count, __entry->type, __entry->p1, __entry->p2)
);
TRACE_EVENT(kvm_book3s_slb_found,
TP_PROTO(unsigned long long gvsid, unsigned long long hvsid),
TP_ARGS(gvsid, hvsid),
TP_STRUCT__entry(
__field( unsigned long long, gvsid )
__field( unsigned long long, hvsid )
),
TP_fast_assign(
__entry->gvsid = gvsid;
__entry->hvsid = hvsid;
),
TP_printk("%llx -> %llx", __entry->gvsid, __entry->hvsid)
);
TRACE_EVENT(kvm_book3s_slb_fail,
TP_PROTO(u16 sid_map_mask, unsigned long long gvsid),
TP_ARGS(sid_map_mask, gvsid),
TP_STRUCT__entry(
__field( unsigned short, sid_map_mask )
__field( unsigned long long, gvsid )
),
TP_fast_assign(
__entry->sid_map_mask = sid_map_mask;
__entry->gvsid = gvsid;
),
TP_printk("%x/%x: %llx", __entry->sid_map_mask,
SID_MAP_MASK - __entry->sid_map_mask, __entry->gvsid)
);
TRACE_EVENT(kvm_book3s_slb_map,
TP_PROTO(u16 sid_map_mask, unsigned long long gvsid,
unsigned long long hvsid),
TP_ARGS(sid_map_mask, gvsid, hvsid),
TP_STRUCT__entry(
__field( unsigned short, sid_map_mask )
__field( unsigned long long, guest_vsid )
__field( unsigned long long, host_vsid )
),
TP_fast_assign(
__entry->sid_map_mask = sid_map_mask;
__entry->guest_vsid = gvsid;
__entry->host_vsid = hvsid;
),
TP_printk("%x: %llx -> %llx", __entry->sid_map_mask,
__entry->guest_vsid, __entry->host_vsid)
);
TRACE_EVENT(kvm_book3s_slbmte,
TP_PROTO(u64 slb_vsid, u64 slb_esid),
TP_ARGS(slb_vsid, slb_esid),
TP_STRUCT__entry(
__field( u64, slb_vsid )
__field( u64, slb_esid )
),
TP_fast_assign(
__entry->slb_vsid = slb_vsid;
__entry->slb_esid = slb_esid;
),
TP_printk("%llx, %llx", __entry->slb_vsid, __entry->slb_esid)
);
TRACE_EVENT(kvm_exit,
TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
TP_ARGS(exit_nr, vcpu),
TP_STRUCT__entry(
__field( unsigned int, exit_nr )
__field( unsigned long, pc )
__field( unsigned long, msr )
__field( unsigned long, dar )
__field( unsigned long, srr1 )
__field( unsigned long, last_inst )
),
TP_fast_assign(
__entry->exit_nr = exit_nr;
__entry->pc = kvmppc_get_pc(vcpu);
__entry->dar = kvmppc_get_fault_dar(vcpu);
__entry->msr = vcpu->arch.shared->msr;
__entry->srr1 = vcpu->arch.shadow_srr1;
__entry->last_inst = vcpu->arch.last_inst;
),
TP_printk("exit=%s"
" | pc=0x%lx"
" | msr=0x%lx"
" | dar=0x%lx"
" | srr1=0x%lx"
" | last_inst=0x%lx"
,
__print_symbolic(__entry->exit_nr, kvm_trace_symbol_exit),
__entry->pc,
__entry->msr,
__entry->dar,
__entry->srr1,
__entry->last_inst
)
);
TRACE_EVENT(kvm_unmap_hva,
TP_PROTO(unsigned long hva),
TP_ARGS(hva),
TP_STRUCT__entry(
__field( unsigned long, hva )
),
TP_fast_assign(
__entry->hva = hva;
),
TP_printk("unmap hva 0x%lx\n", __entry->hva)
);
#endif /* _TRACE_KVM_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View file

@ -38,13 +38,6 @@ struct sca_block {
struct sca_entry cpu[64]; struct sca_entry cpu[64];
} __attribute__((packed)); } __attribute__((packed));
#define KVM_NR_PAGE_SIZES 2
#define KVM_HPAGE_GFN_SHIFT(x) (((x) - 1) * 8)
#define KVM_HPAGE_SHIFT(x) (PAGE_SHIFT + KVM_HPAGE_GFN_SHIFT(x))
#define KVM_HPAGE_SIZE(x) (1UL << KVM_HPAGE_SHIFT(x))
#define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1))
#define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE)
#define CPUSTAT_STOPPED 0x80000000 #define CPUSTAT_STOPPED 0x80000000
#define CPUSTAT_WAIT 0x10000000 #define CPUSTAT_WAIT 0x10000000
#define CPUSTAT_ECALL_PEND 0x08000000 #define CPUSTAT_ECALL_PEND 0x08000000
@ -220,7 +213,6 @@ struct kvm_s390_interrupt_info {
/* for local_interrupt.action_flags */ /* for local_interrupt.action_flags */
#define ACTION_STORE_ON_STOP (1<<0) #define ACTION_STORE_ON_STOP (1<<0)
#define ACTION_STOP_ON_STOP (1<<1) #define ACTION_STOP_ON_STOP (1<<1)
#define ACTION_RELOADVCPU_ON_STOP (1<<2)
struct kvm_s390_local_interrupt { struct kvm_s390_local_interrupt {
spinlock_t lock; spinlock_t lock;

View file

@ -107,14 +107,13 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu) static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu)
{ {
int ret, idx; int ret;
/* No virtio-ccw notification? Get out quickly. */ /* No virtio-ccw notification? Get out quickly. */
if (!vcpu->kvm->arch.css_support || if (!vcpu->kvm->arch.css_support ||
(vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY)) (vcpu->run->s.regs.gprs[1] != KVM_S390_VIRTIO_CCW_NOTIFY))
return -EOPNOTSUPP; return -EOPNOTSUPP;
idx = srcu_read_lock(&vcpu->kvm->srcu);
/* /*
* The layout is as follows: * The layout is as follows:
* - gpr 2 contains the subchannel id (passed as addr) * - gpr 2 contains the subchannel id (passed as addr)
@ -125,7 +124,6 @@ static int __diag_virtio_hypercall(struct kvm_vcpu *vcpu)
vcpu->run->s.regs.gprs[2], vcpu->run->s.regs.gprs[2],
8, &vcpu->run->s.regs.gprs[3], 8, &vcpu->run->s.regs.gprs[3],
vcpu->run->s.regs.gprs[4]); vcpu->run->s.regs.gprs[4]);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
/* /*
* Return cookie in gpr 2, but don't overwrite the register if the * Return cookie in gpr 2, but don't overwrite the register if the

View file

@ -18,20 +18,27 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "kvm-s390.h" #include "kvm-s390.h"
/* Convert real to absolute address by applying the prefix of the CPU */
static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu,
unsigned long gaddr)
{
unsigned long prefix = vcpu->arch.sie_block->prefix;
if (gaddr < 2 * PAGE_SIZE)
gaddr += prefix;
else if (gaddr >= prefix && gaddr < prefix + 2 * PAGE_SIZE)
gaddr -= prefix;
return gaddr;
}
static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu, static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu,
void __user *gptr, void __user *gptr,
int prefixing) int prefixing)
{ {
unsigned long prefix = vcpu->arch.sie_block->prefix;
unsigned long gaddr = (unsigned long) gptr; unsigned long gaddr = (unsigned long) gptr;
unsigned long uaddr; unsigned long uaddr;
if (prefixing) { if (prefixing)
if (gaddr < 2 * PAGE_SIZE) gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
gaddr += prefix;
else if ((gaddr >= prefix) && (gaddr < prefix + 2 * PAGE_SIZE))
gaddr -= prefix;
}
uaddr = gmap_fault(gaddr, vcpu->arch.gmap); uaddr = gmap_fault(gaddr, vcpu->arch.gmap);
if (IS_ERR_VALUE(uaddr)) if (IS_ERR_VALUE(uaddr))
uaddr = -EFAULT; uaddr = -EFAULT;

View file

@ -62,12 +62,6 @@ static int handle_stop(struct kvm_vcpu *vcpu)
trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits); trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits);
if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
rc = SIE_INTERCEPT_RERUNVCPU;
vcpu->run->exit_reason = KVM_EXIT_INTR;
}
if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) {
atomic_set_mask(CPUSTAT_STOPPED, atomic_set_mask(CPUSTAT_STOPPED,
&vcpu->arch.sie_block->cpuflags); &vcpu->arch.sie_block->cpuflags);

Some files were not shown because too many files have changed in this diff Show more