You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branch 'remotes/powerpc/topic/ppc-kvm' into kvm-ppc-next
This merges in the POWER9 radix MMU host and guest support, which was put into a topic branch because it touches both powerpc and KVM code. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
@@ -3201,6 +3201,71 @@ struct kvm_reinject_control {
|
||||
pit_reinject = 0 (!reinject mode) is recommended, unless running an old
|
||||
operating system that uses the PIT for timing (e.g. Linux 2.4.x).
|
||||
|
||||
4.99 KVM_PPC_CONFIGURE_V3_MMU
|
||||
|
||||
Capability: KVM_CAP_PPC_RADIX_MMU or KVM_CAP_PPC_HASH_MMU_V3
|
||||
Architectures: ppc
|
||||
Type: vm ioctl
|
||||
Parameters: struct kvm_ppc_mmuv3_cfg (in)
|
||||
Returns: 0 on success,
|
||||
-EFAULT if struct kvm_ppc_mmuv3_cfg cannot be read,
|
||||
-EINVAL if the configuration is invalid
|
||||
|
||||
This ioctl controls whether the guest will use radix or HPT (hashed
|
||||
page table) translation, and sets the pointer to the process table for
|
||||
the guest.
|
||||
|
||||
struct kvm_ppc_mmuv3_cfg {
|
||||
__u64 flags;
|
||||
__u64 process_table;
|
||||
};
|
||||
|
||||
There are two bits that can be set in flags; KVM_PPC_MMUV3_RADIX and
|
||||
KVM_PPC_MMUV3_GTSE. KVM_PPC_MMUV3_RADIX, if set, configures the guest
|
||||
to use radix tree translation, and if clear, to use HPT translation.
|
||||
KVM_PPC_MMUV3_GTSE, if set and if KVM permits it, configures the guest
|
||||
to be able to use the global TLB and SLB invalidation instructions;
|
||||
if clear, the guest may not use these instructions.
|
||||
|
||||
The process_table field specifies the address and size of the guest
|
||||
process table, which is in the guest's space. This field is formatted
|
||||
as the second doubleword of the partition table entry, as defined in
|
||||
the Power ISA V3.00, Book III section 5.7.6.1.
|
||||
|
||||
4.100 KVM_PPC_GET_RMMU_INFO
|
||||
|
||||
Capability: KVM_CAP_PPC_RADIX_MMU
|
||||
Architectures: ppc
|
||||
Type: vm ioctl
|
||||
Parameters: struct kvm_ppc_rmmu_info (out)
|
||||
Returns: 0 on success,
|
||||
-EFAULT if struct kvm_ppc_rmmu_info cannot be written,
|
||||
-EINVAL if no useful information can be returned
|
||||
|
||||
This ioctl returns a structure containing two things: (a) a list
|
||||
containing supported radix tree geometries, and (b) a list that maps
|
||||
page sizes to put in the "AP" (actual page size) field for the tlbie
|
||||
(TLB invalidate entry) instruction.
|
||||
|
||||
struct kvm_ppc_rmmu_info {
|
||||
struct kvm_ppc_radix_geom {
|
||||
__u8 page_shift;
|
||||
__u8 level_bits[4];
|
||||
__u8 pad[3];
|
||||
} geometries[8];
|
||||
__u32 ap_encodings[8];
|
||||
};
|
||||
|
||||
The geometries[] field gives up to 8 supported geometries for the
|
||||
radix page table, in terms of the log base 2 of the smallest page
|
||||
size, and the number of bits indexed at each level of the tree, from
|
||||
the PTE level up to the PGD level in that order. Any unused entries
|
||||
will have 0 in the page_shift field.
|
||||
|
||||
The ap_encodings gives the supported page sizes and their AP field
|
||||
encodings, encoded with the AP value in the top 3 bits and the log
|
||||
base 2 of the page size in the bottom 6 bits.
|
||||
|
||||
5. The kvm_run structure
|
||||
------------------------
|
||||
|
||||
@@ -3942,3 +4007,21 @@ In order to use SynIC, it has to be activated by setting this
|
||||
capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
|
||||
will disable the use of APIC hardware virtualization even if supported
|
||||
by the CPU, as it's incompatible with SynIC auto-EOI behavior.
|
||||
|
||||
8.3 KVM_CAP_PPC_RADIX_MMU
|
||||
|
||||
Architectures: ppc
|
||||
|
||||
This capability, if KVM_CHECK_EXTENSION indicates that it is
|
||||
available, means that that the kernel can support guests using the
|
||||
radix MMU defined in Power ISA V3.00 (as implemented in the POWER9
|
||||
processor).
|
||||
|
||||
8.4 KVM_CAP_PPC_HASH_MMU_V3
|
||||
|
||||
Architectures: ppc
|
||||
|
||||
This capability, if KVM_CHECK_EXTENSION indicates that it is
|
||||
available, means that that the kernel can support guests using the
|
||||
hashed page table MMU defined in Power ISA V3.00 (as implemented in
|
||||
the POWER9 processor), including in-memory segment tables.
|
||||
|
||||
@@ -44,10 +44,20 @@ struct patb_entry {
|
||||
};
|
||||
extern struct patb_entry *partition_tb;
|
||||
|
||||
/* Bits in patb0 field */
|
||||
#define PATB_HR (1UL << 63)
|
||||
#define PATB_GR (1UL << 63)
|
||||
#define RPDB_MASK 0x0ffffffffffff00fUL
|
||||
#define RPDB_SHIFT (1UL << 8)
|
||||
#define RTS1_SHIFT 61 /* top 2 bits of radix tree size */
|
||||
#define RTS1_MASK (3UL << RTS1_SHIFT)
|
||||
#define RTS2_SHIFT 5 /* bottom 3 bits of radix tree size */
|
||||
#define RTS2_MASK (7UL << RTS2_SHIFT)
|
||||
#define RPDS_MASK 0x1f /* root page dir. size field */
|
||||
|
||||
/* Bits in patb1 field */
|
||||
#define PATB_GR (1UL << 63) /* guest uses radix; must match HR */
|
||||
#define PRTS_MASK 0x1f /* process table size field */
|
||||
|
||||
/*
|
||||
* Limit process table to PAGE_SIZE table. This
|
||||
* also limit the max pid we can support.
|
||||
@@ -138,5 +148,11 @@ static inline void setup_initial_memory_limit(phys_addr_t first_memblock_base,
|
||||
extern int (*register_process_table)(unsigned long base, unsigned long page_size,
|
||||
unsigned long tbl_size);
|
||||
|
||||
#ifdef CONFIG_PPC_PSERIES
|
||||
extern void radix_init_pseries(void);
|
||||
#else
|
||||
static inline void radix_init_pseries(void) { };
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* _ASM_POWERPC_BOOK3S_64_MMU_H_ */
|
||||
|
||||
@@ -97,6 +97,15 @@
|
||||
ld reg,PACAKBASE(r13); \
|
||||
ori reg,reg,(ABS_ADDR(label))@l;
|
||||
|
||||
/*
|
||||
* Branches from unrelocated code (e.g., interrupts) to labels outside
|
||||
* head-y require >64K offsets.
|
||||
*/
|
||||
#define __LOAD_FAR_HANDLER(reg, label) \
|
||||
ld reg,PACAKBASE(r13); \
|
||||
ori reg,reg,(ABS_ADDR(label))@l; \
|
||||
addis reg,reg,(ABS_ADDR(label))@h;
|
||||
|
||||
/* Exception register prefixes */
|
||||
#define EXC_HV H
|
||||
#define EXC_STD
|
||||
@@ -227,13 +236,41 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
||||
mtctr reg; \
|
||||
bctr
|
||||
|
||||
/*
|
||||
* KVM requires __LOAD_FAR_HANDLER.
|
||||
*
|
||||
* __BRANCH_TO_KVM_EXIT branches are also a special case because they
|
||||
* explicitly use r9 then reload it from PACA before branching. Hence
|
||||
* the double-underscore.
|
||||
*/
|
||||
#define __BRANCH_TO_KVM_EXIT(area, label) \
|
||||
mfctr r9; \
|
||||
std r9,HSTATE_SCRATCH1(r13); \
|
||||
__LOAD_FAR_HANDLER(r9, label); \
|
||||
mtctr r9; \
|
||||
ld r9,area+EX_R9(r13); \
|
||||
bctr
|
||||
|
||||
#define BRANCH_TO_KVM(reg, label) \
|
||||
__LOAD_FAR_HANDLER(reg, label); \
|
||||
mtctr reg; \
|
||||
bctr
|
||||
|
||||
#else
|
||||
#define BRANCH_TO_COMMON(reg, label) \
|
||||
b label
|
||||
|
||||
#define BRANCH_TO_KVM(reg, label) \
|
||||
b label
|
||||
|
||||
#define __BRANCH_TO_KVM_EXIT(area, label) \
|
||||
ld r9,area+EX_R9(r13); \
|
||||
b label
|
||||
|
||||
#endif
|
||||
|
||||
#define __KVM_HANDLER_PROLOG(area, n) \
|
||||
|
||||
#define __KVM_HANDLER(area, h, n) \
|
||||
BEGIN_FTR_SECTION_NESTED(947) \
|
||||
ld r10,area+EX_CFAR(r13); \
|
||||
std r10,HSTATE_CFAR(r13); \
|
||||
@@ -243,30 +280,28 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
||||
std r10,HSTATE_PPR(r13); \
|
||||
END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,948); \
|
||||
ld r10,area+EX_R10(r13); \
|
||||
stw r9,HSTATE_SCRATCH1(r13); \
|
||||
ld r9,area+EX_R9(r13); \
|
||||
std r12,HSTATE_SCRATCH0(r13); \
|
||||
|
||||
#define __KVM_HANDLER(area, h, n) \
|
||||
__KVM_HANDLER_PROLOG(area, n) \
|
||||
li r12,n; \
|
||||
b kvmppc_interrupt
|
||||
sldi r12,r9,32; \
|
||||
ori r12,r12,(n); \
|
||||
/* This reloads r9 before branching to kvmppc_interrupt */ \
|
||||
__BRANCH_TO_KVM_EXIT(area, kvmppc_interrupt)
|
||||
|
||||
#define __KVM_HANDLER_SKIP(area, h, n) \
|
||||
cmpwi r10,KVM_GUEST_MODE_SKIP; \
|
||||
ld r10,area+EX_R10(r13); \
|
||||
beq 89f; \
|
||||
stw r9,HSTATE_SCRATCH1(r13); \
|
||||
BEGIN_FTR_SECTION_NESTED(948) \
|
||||
ld r9,area+EX_PPR(r13); \
|
||||
std r9,HSTATE_PPR(r13); \
|
||||
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 r9,area+EX_R9(r13); \
|
||||
ld r10,area+EX_R10(r13); \
|
||||
std r12,HSTATE_SCRATCH0(r13); \
|
||||
li r12,n; \
|
||||
b kvmppc_interrupt; \
|
||||
sldi r12,r9,32; \
|
||||
ori r12,r12,(n); \
|
||||
/* This reloads r9 before branching to kvmppc_interrupt */ \
|
||||
__BRANCH_TO_KVM_EXIT(area, kvmppc_interrupt); \
|
||||
89: mtocrf 0x80,r9; \
|
||||
ld r9,area+EX_R9(r13); \
|
||||
ld r10,area+EX_R10(r13); \
|
||||
b kvmppc_skip_##h##interrupt
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
@@ -393,12 +428,12 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
||||
EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_STD)
|
||||
|
||||
#define STD_RELON_EXCEPTION_HV(loc, vec, label) \
|
||||
/* No guest interrupts come through here */ \
|
||||
SET_SCRATCH0(r13); /* save r13 */ \
|
||||
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, EXC_HV, NOTEST, vec);
|
||||
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label, \
|
||||
EXC_HV, KVMTEST_HV, vec);
|
||||
|
||||
#define STD_RELON_EXCEPTION_HV_OOL(vec, label) \
|
||||
EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \
|
||||
EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_HV, vec); \
|
||||
EXCEPTION_RELON_PROLOG_PSERIES_1(label, EXC_HV)
|
||||
|
||||
/* This associate vector numbers with bits in paca->irq_happened */
|
||||
@@ -475,10 +510,10 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
||||
|
||||
#define MASKABLE_RELON_EXCEPTION_HV(loc, vec, label) \
|
||||
_MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, \
|
||||
EXC_HV, SOFTEN_NOTEST_HV)
|
||||
EXC_HV, SOFTEN_TEST_HV)
|
||||
|
||||
#define MASKABLE_RELON_EXCEPTION_HV_OOL(vec, label) \
|
||||
EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_NOTEST_HV, vec); \
|
||||
EXCEPTION_PROLOG_1(PACA_EXGEN, SOFTEN_TEST_HV, vec); \
|
||||
EXCEPTION_PROLOG_PSERIES_1(label, EXC_HV)
|
||||
|
||||
/*
|
||||
|
||||
@@ -218,7 +218,7 @@ name:
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
#define TRAMP_KVM_BEGIN(name) \
|
||||
TRAMP_REAL_BEGIN(name)
|
||||
TRAMP_VIRT_BEGIN(name)
|
||||
#else
|
||||
#define TRAMP_KVM_BEGIN(name)
|
||||
#endif
|
||||
|
||||
@@ -276,6 +276,7 @@
|
||||
#define H_GET_MPP_X 0x314
|
||||
#define H_SET_MODE 0x31C
|
||||
#define H_CLEAR_HPT 0x358
|
||||
#define H_REGISTER_PROC_TBL 0x37C
|
||||
#define H_SIGNAL_SYS_RESET 0x380
|
||||
#define MAX_HCALL_OPCODE H_SIGNAL_SYS_RESET
|
||||
|
||||
@@ -313,6 +314,16 @@
|
||||
#define H_SIGNAL_SYS_RESET_ALL_OTHERS -2
|
||||
/* >= 0 values are CPU number */
|
||||
|
||||
/* Flag values used in H_REGISTER_PROC_TBL hcall */
|
||||
#define PROC_TABLE_OP_MASK 0x18
|
||||
#define PROC_TABLE_DEREG 0x10
|
||||
#define PROC_TABLE_NEW 0x18
|
||||
#define PROC_TABLE_TYPE_MASK 0x06
|
||||
#define PROC_TABLE_HPT_SLB 0x00
|
||||
#define PROC_TABLE_HPT_PT 0x02
|
||||
#define PROC_TABLE_RADIX 0x04
|
||||
#define PROC_TABLE_GTSE 0x01
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/**
|
||||
|
||||
@@ -170,6 +170,8 @@ extern int kvmppc_book3s_hv_page_fault(struct kvm_run *run,
|
||||
unsigned long status);
|
||||
extern long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr,
|
||||
unsigned long slb_v, unsigned long valid);
|
||||
extern int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned long gpa, gva_t ea, int is_store);
|
||||
|
||||
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);
|
||||
@@ -182,6 +184,25 @@ extern void kvmppc_mmu_hpte_sysexit(void);
|
||||
extern int kvmppc_mmu_hv_init(void);
|
||||
extern int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hc);
|
||||
|
||||
extern int kvmppc_book3s_radix_page_fault(struct kvm_run *run,
|
||||
struct kvm_vcpu *vcpu,
|
||||
unsigned long ea, unsigned long dsisr);
|
||||
extern int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
|
||||
struct kvmppc_pte *gpte, bool data, bool iswrite);
|
||||
extern int kvmppc_init_vm_radix(struct kvm *kvm);
|
||||
extern void kvmppc_free_radix(struct kvm *kvm);
|
||||
extern int kvmppc_radix_init(void);
|
||||
extern void kvmppc_radix_exit(void);
|
||||
extern int kvm_unmap_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn);
|
||||
extern int kvm_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn);
|
||||
extern int kvm_test_age_radix(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn);
|
||||
extern long kvmppc_hv_get_dirty_log_radix(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot, unsigned long *map);
|
||||
extern int kvmhv_get_rmmu_info(struct kvm *kvm, struct kvm_ppc_rmmu_info *info);
|
||||
|
||||
/* XXX remove this export when load_last_inst() is generic */
|
||||
extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, bool data);
|
||||
extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec);
|
||||
@@ -211,8 +232,11 @@ extern long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
|
||||
extern long kvmppc_do_h_remove(struct kvm *kvm, unsigned long flags,
|
||||
unsigned long pte_index, unsigned long avpn,
|
||||
unsigned long *hpret);
|
||||
extern long kvmppc_hv_get_dirty_log(struct kvm *kvm,
|
||||
extern long kvmppc_hv_get_dirty_log_hpt(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot, unsigned long *map);
|
||||
extern void kvmppc_harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
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_set_fscr(struct kvm_vcpu *vcpu, u64 fscr);
|
||||
|
||||
@@ -36,6 +36,12 @@ static inline void svcpu_put(struct kvmppc_book3s_shadow_vcpu *svcpu)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
|
||||
static inline bool kvm_is_radix(struct kvm *kvm)
|
||||
{
|
||||
return kvm->arch.radix;
|
||||
}
|
||||
|
||||
#define KVM_DEFAULT_HPT_ORDER 24 /* 16MB HPT by default */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -263,7 +263,11 @@ struct kvm_arch {
|
||||
unsigned long hpt_mask;
|
||||
atomic_t hpte_mod_interest;
|
||||
cpumask_t need_tlb_flush;
|
||||
cpumask_t cpu_in_guest;
|
||||
int hpt_cma_alloc;
|
||||
u8 radix;
|
||||
pgd_t *pgtable;
|
||||
u64 process_table;
|
||||
struct dentry *debugfs_dir;
|
||||
struct dentry *htab_dentry;
|
||||
#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
|
||||
@@ -603,6 +607,7 @@ struct kvm_vcpu_arch {
|
||||
ulong fault_dar;
|
||||
u32 fault_dsisr;
|
||||
unsigned long intr_msr;
|
||||
ulong fault_gpa; /* guest real address of page fault (POWER9) */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOKE
|
||||
@@ -657,6 +662,7 @@ struct kvm_vcpu_arch {
|
||||
int state;
|
||||
int ptid;
|
||||
int thread_cpu;
|
||||
int prev_cpu;
|
||||
bool timer_running;
|
||||
wait_queue_head_t cpu_run;
|
||||
|
||||
|
||||
@@ -291,6 +291,8 @@ struct kvmppc_ops {
|
||||
struct irq_bypass_producer *);
|
||||
void (*irq_bypass_del_producer)(struct irq_bypass_consumer *,
|
||||
struct irq_bypass_producer *);
|
||||
int (*configure_mmu)(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg);
|
||||
int (*get_rmmu_info)(struct kvm *kvm, struct kvm_ppc_rmmu_info *info);
|
||||
};
|
||||
|
||||
extern struct kvmppc_ops *kvmppc_hv_ops;
|
||||
|
||||
@@ -121,6 +121,8 @@ struct of_drconf_cell {
|
||||
#define OV1_PPC_2_06 0x02 /* set if we support PowerPC 2.06 */
|
||||
#define OV1_PPC_2_07 0x01 /* set if we support PowerPC 2.07 */
|
||||
|
||||
#define OV1_PPC_3_00 0x80 /* set if we support PowerPC 3.00 */
|
||||
|
||||
/* Option vector 2: Open Firmware options supported */
|
||||
#define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */
|
||||
|
||||
@@ -151,10 +153,17 @@ struct of_drconf_cell {
|
||||
#define OV5_XCMO 0x0440 /* Page Coalescing */
|
||||
#define OV5_TYPE1_AFFINITY 0x0580 /* Type 1 NUMA affinity */
|
||||
#define OV5_PRRN 0x0540 /* Platform Resource Reassignment */
|
||||
#define OV5_PFO_HW_RNG 0x0E80 /* PFO Random Number Generator */
|
||||
#define OV5_PFO_HW_842 0x0E40 /* PFO Compression Accelerator */
|
||||
#define OV5_PFO_HW_ENCR 0x0E20 /* PFO Encryption Accelerator */
|
||||
#define OV5_SUB_PROCESSORS 0x0F01 /* 1,2,or 4 Sub-Processors supported */
|
||||
#define OV5_PFO_HW_RNG 0x1180 /* PFO Random Number Generator */
|
||||
#define OV5_PFO_HW_842 0x1140 /* PFO Compression Accelerator */
|
||||
#define OV5_PFO_HW_ENCR 0x1120 /* PFO Encryption Accelerator */
|
||||
#define OV5_SUB_PROCESSORS 0x1501 /* 1,2,or 4 Sub-Processors supported */
|
||||
#define OV5_XIVE_EXPLOIT 0x1701 /* XIVE exploitation supported */
|
||||
#define OV5_MMU_RADIX_300 0x1880 /* ISA v3.00 radix MMU supported */
|
||||
#define OV5_MMU_HASH_300 0x1840 /* ISA v3.00 hash MMU supported */
|
||||
#define OV5_MMU_SEGM_RADIX 0x1820 /* radix mode (no segmentation) */
|
||||
#define OV5_MMU_PROC_TBL 0x1810 /* hcall selects SLB or proc table */
|
||||
#define OV5_MMU_SLB 0x1800 /* always use SLB */
|
||||
#define OV5_MMU_GTSE 0x1808 /* Guest translation shootdown */
|
||||
|
||||
/* Option Vector 6: IBM PAPR hints */
|
||||
#define OV6_LINUX 0x02 /* Linux is our OS */
|
||||
|
||||
@@ -274,10 +274,14 @@
|
||||
#define SPRN_DSISR 0x012 /* Data Storage Interrupt Status Register */
|
||||
#define DSISR_NOHPTE 0x40000000 /* no translation found */
|
||||
#define DSISR_PROTFAULT 0x08000000 /* protection fault */
|
||||
#define DSISR_BADACCESS 0x04000000 /* bad access to CI or G */
|
||||
#define DSISR_ISSTORE 0x02000000 /* access was a store */
|
||||
#define DSISR_DABRMATCH 0x00400000 /* hit data breakpoint */
|
||||
#define DSISR_NOSEGMENT 0x00200000 /* SLB miss */
|
||||
#define DSISR_KEYFAULT 0x00200000 /* Key fault */
|
||||
#define DSISR_UNSUPP_MMU 0x00080000 /* Unsupported MMU config */
|
||||
#define DSISR_SET_RC 0x00040000 /* Failed setting of R/C bits */
|
||||
#define DSISR_PGDIRFAULT 0x00020000 /* Fault on page directory */
|
||||
#define SPRN_TBRL 0x10C /* Time Base Read Lower Register (user, R/O) */
|
||||
#define SPRN_TBRU 0x10D /* Time Base Read Upper Register (user, R/O) */
|
||||
#define SPRN_CIR 0x11B /* Chip Information Register (hyper, R/0) */
|
||||
|
||||
@@ -413,6 +413,26 @@ struct kvm_get_htab_header {
|
||||
__u16 n_invalid;
|
||||
};
|
||||
|
||||
/* For KVM_PPC_CONFIGURE_V3_MMU */
|
||||
struct kvm_ppc_mmuv3_cfg {
|
||||
__u64 flags;
|
||||
__u64 process_table; /* second doubleword of partition table entry */
|
||||
};
|
||||
|
||||
/* Flag values for KVM_PPC_CONFIGURE_V3_MMU */
|
||||
#define KVM_PPC_MMUV3_RADIX 1 /* 1 = radix mode, 0 = HPT */
|
||||
#define KVM_PPC_MMUV3_GTSE 2 /* global translation shootdown enb. */
|
||||
|
||||
/* For KVM_PPC_GET_RMMU_INFO */
|
||||
struct kvm_ppc_rmmu_info {
|
||||
struct kvm_ppc_radix_geom {
|
||||
__u8 page_shift;
|
||||
__u8 level_bits[4];
|
||||
__u8 pad[3];
|
||||
} geometries[8];
|
||||
__u32 ap_encodings[8];
|
||||
};
|
||||
|
||||
/* Per-vcpu XICS interrupt controller state */
|
||||
#define KVM_REG_PPC_ICP_STATE (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x8c)
|
||||
|
||||
|
||||
@@ -498,6 +498,7 @@ int main(void)
|
||||
DEFINE(KVM_NEED_FLUSH, offsetof(struct kvm, arch.need_tlb_flush.bits));
|
||||
DEFINE(KVM_ENABLED_HCALLS, offsetof(struct kvm, arch.enabled_hcalls));
|
||||
DEFINE(KVM_VRMA_SLB_V, offsetof(struct kvm, arch.vrma_slb_v));
|
||||
DEFINE(KVM_RADIX, offsetof(struct kvm, arch.radix));
|
||||
DEFINE(VCPU_DSISR, offsetof(struct kvm_vcpu, arch.shregs.dsisr));
|
||||
DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
|
||||
DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
|
||||
@@ -537,6 +538,7 @@ int main(void)
|
||||
DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
|
||||
DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr));
|
||||
DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
|
||||
DEFINE(VCPU_FAULT_GPA, offsetof(struct kvm_vcpu, arch.fault_gpa));
|
||||
DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
|
||||
DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
|
||||
DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
|
||||
|
||||
@@ -142,7 +142,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_300)
|
||||
lbz r0,HSTATE_HWTHREAD_REQ(r13)
|
||||
cmpwi r0,0
|
||||
beq 1f
|
||||
b kvm_start_guest
|
||||
BRANCH_TO_KVM(r10, kvm_start_guest)
|
||||
1:
|
||||
#endif
|
||||
|
||||
@@ -717,13 +717,9 @@ hardware_interrupt_hv:
|
||||
BEGIN_FTR_SECTION
|
||||
_MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
|
||||
EXC_HV, SOFTEN_TEST_HV)
|
||||
do_kvm_H0x500:
|
||||
KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x502)
|
||||
FTR_SECTION_ELSE
|
||||
_MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt_common,
|
||||
EXC_STD, SOFTEN_TEST_PR)
|
||||
do_kvm_0x500:
|
||||
KVM_HANDLER(PACA_EXGEN, EXC_STD, 0x500)
|
||||
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
|
||||
EXC_REAL_END(hardware_interrupt, 0x500, 0x600)
|
||||
|
||||
@@ -737,6 +733,8 @@ hardware_interrupt_relon_hv:
|
||||
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
|
||||
EXC_VIRT_END(hardware_interrupt, 0x4500, 0x4600)
|
||||
|
||||
TRAMP_KVM(PACA_EXGEN, 0x500)
|
||||
TRAMP_KVM_HV(PACA_EXGEN, 0x500)
|
||||
EXC_COMMON_ASYNC(hardware_interrupt_common, 0x500, do_IRQ)
|
||||
|
||||
|
||||
@@ -832,6 +830,31 @@ EXC_VIRT(trap_0b, 0x4b00, 0x4c00, 0xb00)
|
||||
TRAMP_KVM(PACA_EXGEN, 0xb00)
|
||||
EXC_COMMON(trap_0b_common, 0xb00, unknown_exception)
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
/*
|
||||
* If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
|
||||
* that support it) before changing to HMT_MEDIUM. That allows the KVM
|
||||
* code to save that value into the guest state (it is the guest's PPR
|
||||
* value). Otherwise just change to HMT_MEDIUM as userspace has
|
||||
* already saved the PPR.
|
||||
*/
|
||||
#define SYSCALL_KVMTEST \
|
||||
SET_SCRATCH0(r13); \
|
||||
GET_PACA(r13); \
|
||||
std r9,PACA_EXGEN+EX_R9(r13); \
|
||||
OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR); \
|
||||
HMT_MEDIUM; \
|
||||
std r10,PACA_EXGEN+EX_R10(r13); \
|
||||
OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR); \
|
||||
mfcr r9; \
|
||||
KVMTEST_PR(0xc00); \
|
||||
GET_SCRATCH0(r13)
|
||||
|
||||
#else
|
||||
#define SYSCALL_KVMTEST \
|
||||
HMT_MEDIUM
|
||||
#endif
|
||||
|
||||
#define LOAD_SYSCALL_HANDLER(reg) \
|
||||
__LOAD_HANDLER(reg, system_call_common)
|
||||
|
||||
@@ -885,34 +908,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \
|
||||
#endif
|
||||
|
||||
EXC_REAL_BEGIN(system_call, 0xc00, 0xd00)
|
||||
/*
|
||||
* If CONFIG_KVM_BOOK3S_64_HANDLER is set, save the PPR (on systems
|
||||
* that support it) before changing to HMT_MEDIUM. That allows the KVM
|
||||
* code to save that value into the guest state (it is the guest's PPR
|
||||
* value). Otherwise just change to HMT_MEDIUM as userspace has
|
||||
* already saved the PPR.
|
||||
*/
|
||||
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
|
||||
SET_SCRATCH0(r13)
|
||||
GET_PACA(r13)
|
||||
std r9,PACA_EXGEN+EX_R9(r13)
|
||||
OPT_GET_SPR(r9, SPRN_PPR, CPU_FTR_HAS_PPR);
|
||||
HMT_MEDIUM;
|
||||
std r10,PACA_EXGEN+EX_R10(r13)
|
||||
OPT_SAVE_REG_TO_PACA(PACA_EXGEN+EX_PPR, r9, CPU_FTR_HAS_PPR);
|
||||
mfcr r9
|
||||
KVMTEST_PR(0xc00)
|
||||
GET_SCRATCH0(r13)
|
||||
#else
|
||||
HMT_MEDIUM;
|
||||
#endif
|
||||
SYSCALL_KVMTEST
|
||||
SYSCALL_PSERIES_1
|
||||
SYSCALL_PSERIES_2_RFID
|
||||
SYSCALL_PSERIES_3
|
||||
EXC_REAL_END(system_call, 0xc00, 0xd00)
|
||||
|
||||
EXC_VIRT_BEGIN(system_call, 0x4c00, 0x4d00)
|
||||
HMT_MEDIUM
|
||||
SYSCALL_KVMTEST
|
||||
SYSCALL_PSERIES_1
|
||||
SYSCALL_PSERIES_2_DIRECT
|
||||
SYSCALL_PSERIES_3
|
||||
@@ -927,7 +930,7 @@ TRAMP_KVM(PACA_EXGEN, 0xd00)
|
||||
EXC_COMMON(single_step_common, 0xd00, single_step_exception)
|
||||
|
||||
EXC_REAL_OOL_HV(h_data_storage, 0xe00, 0xe20)
|
||||
EXC_VIRT_NONE(0x4e00, 0x4e20)
|
||||
EXC_VIRT_OOL_HV(h_data_storage, 0x4e00, 0x4e20, 0xe00)
|
||||
TRAMP_KVM_HV_SKIP(PACA_EXGEN, 0xe00)
|
||||
EXC_COMMON_BEGIN(h_data_storage_common)
|
||||
mfspr r10,SPRN_HDAR
|
||||
@@ -943,7 +946,7 @@ EXC_COMMON_BEGIN(h_data_storage_common)
|
||||
|
||||
|
||||
EXC_REAL_OOL_HV(h_instr_storage, 0xe20, 0xe40)
|
||||
EXC_VIRT_NONE(0x4e20, 0x4e40)
|
||||
EXC_VIRT_OOL_HV(h_instr_storage, 0x4e20, 0x4e40, 0xe20)
|
||||
TRAMP_KVM_HV(PACA_EXGEN, 0xe20)
|
||||
EXC_COMMON(h_instr_storage_common, 0xe20, unknown_exception)
|
||||
|
||||
|
||||
@@ -649,6 +649,7 @@ static void __init early_cmdline_parse(void)
|
||||
struct option_vector1 {
|
||||
u8 byte1;
|
||||
u8 arch_versions;
|
||||
u8 arch_versions3;
|
||||
} __packed;
|
||||
|
||||
struct option_vector2 {
|
||||
@@ -691,6 +692,9 @@ struct option_vector5 {
|
||||
u8 reserved2;
|
||||
__be16 reserved3;
|
||||
u8 subprocessors;
|
||||
u8 byte22;
|
||||
u8 intarch;
|
||||
u8 mmu;
|
||||
} __packed;
|
||||
|
||||
struct option_vector6 {
|
||||
@@ -700,7 +704,7 @@ struct option_vector6 {
|
||||
} __packed;
|
||||
|
||||
struct ibm_arch_vec {
|
||||
struct { u32 mask, val; } pvrs[10];
|
||||
struct { u32 mask, val; } pvrs[12];
|
||||
|
||||
u8 num_vectors;
|
||||
|
||||
@@ -749,6 +753,14 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
|
||||
.mask = cpu_to_be32(0xffff0000), /* POWER8 */
|
||||
.val = cpu_to_be32(0x004d0000),
|
||||
},
|
||||
{
|
||||
.mask = cpu_to_be32(0xffff0000), /* POWER9 */
|
||||
.val = cpu_to_be32(0x004e0000),
|
||||
},
|
||||
{
|
||||
.mask = cpu_to_be32(0xffffffff), /* all 3.00-compliant */
|
||||
.val = cpu_to_be32(0x0f000005),
|
||||
},
|
||||
{
|
||||
.mask = cpu_to_be32(0xffffffff), /* all 2.07-compliant */
|
||||
.val = cpu_to_be32(0x0f000004),
|
||||
@@ -774,6 +786,7 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
|
||||
.byte1 = 0,
|
||||
.arch_versions = OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
|
||||
OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07,
|
||||
.arch_versions3 = OV1_PPC_3_00,
|
||||
},
|
||||
|
||||
.vec2_len = VECTOR_LENGTH(sizeof(struct option_vector2)),
|
||||
@@ -836,6 +849,9 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
|
||||
.reserved2 = 0,
|
||||
.reserved3 = 0,
|
||||
.subprocessors = 1,
|
||||
.intarch = 0,
|
||||
.mmu = OV5_FEAT(OV5_MMU_RADIX_300) | OV5_FEAT(OV5_MMU_HASH_300) |
|
||||
OV5_FEAT(OV5_MMU_PROC_TBL) | OV5_FEAT(OV5_MMU_GTSE),
|
||||
},
|
||||
|
||||
/* option vector 6: IBM PAPR hints */
|
||||
|
||||
@@ -70,7 +70,8 @@ endif
|
||||
kvm-hv-y += \
|
||||
book3s_hv.o \
|
||||
book3s_hv_interrupts.o \
|
||||
book3s_64_mmu_hv.o
|
||||
book3s_64_mmu_hv.o \
|
||||
book3s_64_mmu_radix.o
|
||||
|
||||
kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \
|
||||
book3s_hv_rm_xics.o
|
||||
|
||||
@@ -239,6 +239,7 @@ void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar,
|
||||
kvmppc_set_dsisr(vcpu, flags);
|
||||
kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvmppc_core_queue_data_storage); /* used by kvm_hv */
|
||||
|
||||
void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong flags)
|
||||
{
|
||||
|
||||
@@ -119,6 +119,9 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
|
||||
long err = -EBUSY;
|
||||
long order;
|
||||
|
||||
if (kvm_is_radix(kvm))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
if (kvm->arch.hpte_setup_done) {
|
||||
kvm->arch.hpte_setup_done = 0;
|
||||
@@ -152,12 +155,11 @@ long kvmppc_alloc_reset_hpt(struct kvm *kvm, u32 *htab_orderp)
|
||||
|
||||
void kvmppc_free_hpt(struct kvm *kvm)
|
||||
{
|
||||
kvmppc_free_lpid(kvm->arch.lpid);
|
||||
vfree(kvm->arch.revmap);
|
||||
if (kvm->arch.hpt_cma_alloc)
|
||||
kvm_release_hpt(virt_to_page(kvm->arch.hpt_virt),
|
||||
1 << (kvm->arch.hpt_order - PAGE_SHIFT));
|
||||
else
|
||||
else if (kvm->arch.hpt_virt)
|
||||
free_pages(kvm->arch.hpt_virt,
|
||||
kvm->arch.hpt_order - PAGE_SHIFT);
|
||||
}
|
||||
@@ -392,8 +394,8 @@ static int instruction_is_store(unsigned int instr)
|
||||
return (instr & mask) != 0;
|
||||
}
|
||||
|
||||
static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned long gpa, gva_t ea, int is_store)
|
||||
int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned long gpa, gva_t ea, int is_store)
|
||||
{
|
||||
u32 last_inst;
|
||||
|
||||
@@ -458,6 +460,9 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
|
||||
unsigned long rcbits;
|
||||
long mmio_update;
|
||||
|
||||
if (kvm_is_radix(kvm))
|
||||
return kvmppc_book3s_radix_page_fault(run, vcpu, ea, dsisr);
|
||||
|
||||
/*
|
||||
* Real-mode code has already searched the HPT and found the
|
||||
* entry we're interested in. Lock the entry and check that
|
||||
@@ -695,12 +700,13 @@ static void kvmppc_rmap_reset(struct kvm *kvm)
|
||||
srcu_read_unlock(&kvm->srcu, srcu_idx);
|
||||
}
|
||||
|
||||
typedef int (*hva_handler_fn)(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn);
|
||||
|
||||
static int kvm_handle_hva_range(struct kvm *kvm,
|
||||
unsigned long start,
|
||||
unsigned long end,
|
||||
int (*handler)(struct kvm *kvm,
|
||||
unsigned long *rmapp,
|
||||
unsigned long gfn))
|
||||
hva_handler_fn handler)
|
||||
{
|
||||
int ret;
|
||||
int retval = 0;
|
||||
@@ -725,9 +731,7 @@ static int kvm_handle_hva_range(struct kvm *kvm,
|
||||
gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
|
||||
|
||||
for (; gfn < gfn_end; ++gfn) {
|
||||
gfn_t gfn_offset = gfn - memslot->base_gfn;
|
||||
|
||||
ret = handler(kvm, &memslot->arch.rmap[gfn_offset], gfn);
|
||||
ret = handler(kvm, memslot, gfn);
|
||||
retval |= ret;
|
||||
}
|
||||
}
|
||||
@@ -736,20 +740,21 @@ static int kvm_handle_hva_range(struct kvm *kvm,
|
||||
}
|
||||
|
||||
static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
|
||||
int (*handler)(struct kvm *kvm, unsigned long *rmapp,
|
||||
unsigned long gfn))
|
||||
hva_handler_fn handler)
|
||||
{
|
||||
return kvm_handle_hva_range(kvm, hva, hva + 1, handler);
|
||||
}
|
||||
|
||||
static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn)
|
||||
{
|
||||
struct revmap_entry *rev = kvm->arch.revmap;
|
||||
unsigned long h, i, j;
|
||||
__be64 *hptep;
|
||||
unsigned long ptel, psize, rcbits;
|
||||
unsigned long *rmapp;
|
||||
|
||||
rmapp = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
for (;;) {
|
||||
lock_rmap(rmapp);
|
||||
if (!(*rmapp & KVMPPC_RMAP_PRESENT)) {
|
||||
@@ -810,26 +815,36 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
|
||||
int kvm_unmap_hva_hv(struct kvm *kvm, unsigned long hva)
|
||||
{
|
||||
kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
|
||||
hva_handler_fn handler;
|
||||
|
||||
handler = kvm_is_radix(kvm) ? kvm_unmap_radix : kvm_unmap_rmapp;
|
||||
kvm_handle_hva(kvm, hva, handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_unmap_hva_range_hv(struct kvm *kvm, unsigned long start, unsigned long end)
|
||||
{
|
||||
kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp);
|
||||
hva_handler_fn handler;
|
||||
|
||||
handler = kvm_is_radix(kvm) ? kvm_unmap_radix : kvm_unmap_rmapp;
|
||||
kvm_handle_hva_range(kvm, start, end, handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvmppc_core_flush_memslot_hv(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot)
|
||||
{
|
||||
unsigned long *rmapp;
|
||||
unsigned long gfn;
|
||||
unsigned long n;
|
||||
unsigned long *rmapp;
|
||||
|
||||
rmapp = memslot->arch.rmap;
|
||||
gfn = memslot->base_gfn;
|
||||
for (n = memslot->npages; n; --n) {
|
||||
rmapp = memslot->arch.rmap;
|
||||
for (n = memslot->npages; n; --n, ++gfn) {
|
||||
if (kvm_is_radix(kvm)) {
|
||||
kvm_unmap_radix(kvm, memslot, gfn);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Testing the present bit without locking is OK because
|
||||
* the memslot has been marked invalid already, and hence
|
||||
@@ -837,20 +852,21 @@ void kvmppc_core_flush_memslot_hv(struct kvm *kvm,
|
||||
* thus the present bit can't go from 0 to 1.
|
||||
*/
|
||||
if (*rmapp & KVMPPC_RMAP_PRESENT)
|
||||
kvm_unmap_rmapp(kvm, rmapp, gfn);
|
||||
kvm_unmap_rmapp(kvm, memslot, gfn);
|
||||
++rmapp;
|
||||
++gfn;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
static int kvm_age_rmapp(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn)
|
||||
{
|
||||
struct revmap_entry *rev = kvm->arch.revmap;
|
||||
unsigned long head, i, j;
|
||||
__be64 *hptep;
|
||||
int ret = 0;
|
||||
unsigned long *rmapp;
|
||||
|
||||
rmapp = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
retry:
|
||||
lock_rmap(rmapp);
|
||||
if (*rmapp & KVMPPC_RMAP_REFERENCED) {
|
||||
@@ -898,17 +914,22 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
|
||||
int kvm_age_hva_hv(struct kvm *kvm, unsigned long start, unsigned long end)
|
||||
{
|
||||
return kvm_handle_hva_range(kvm, start, end, kvm_age_rmapp);
|
||||
hva_handler_fn handler;
|
||||
|
||||
handler = kvm_is_radix(kvm) ? kvm_age_radix : kvm_age_rmapp;
|
||||
return kvm_handle_hva_range(kvm, start, end, handler);
|
||||
}
|
||||
|
||||
static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
static int kvm_test_age_rmapp(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long gfn)
|
||||
{
|
||||
struct revmap_entry *rev = kvm->arch.revmap;
|
||||
unsigned long head, i, j;
|
||||
unsigned long *hp;
|
||||
int ret = 1;
|
||||
unsigned long *rmapp;
|
||||
|
||||
rmapp = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
if (*rmapp & KVMPPC_RMAP_REFERENCED)
|
||||
return 1;
|
||||
|
||||
@@ -934,12 +955,18 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
|
||||
|
||||
int kvm_test_age_hva_hv(struct kvm *kvm, unsigned long hva)
|
||||
{
|
||||
return kvm_handle_hva(kvm, hva, kvm_test_age_rmapp);
|
||||
hva_handler_fn handler;
|
||||
|
||||
handler = kvm_is_radix(kvm) ? kvm_test_age_radix : kvm_test_age_rmapp;
|
||||
return kvm_handle_hva(kvm, hva, handler);
|
||||
}
|
||||
|
||||
void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte)
|
||||
{
|
||||
kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
|
||||
hva_handler_fn handler;
|
||||
|
||||
handler = kvm_is_radix(kvm) ? kvm_unmap_radix : kvm_unmap_rmapp;
|
||||
kvm_handle_hva(kvm, hva, handler);
|
||||
}
|
||||
|
||||
static int vcpus_running(struct kvm *kvm)
|
||||
@@ -1040,7 +1067,7 @@ static int kvm_test_clear_dirty_npages(struct kvm *kvm, unsigned long *rmapp)
|
||||
return npages_dirty;
|
||||
}
|
||||
|
||||
static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
void kvmppc_harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
struct kvm_memory_slot *memslot,
|
||||
unsigned long *map)
|
||||
{
|
||||
@@ -1058,12 +1085,11 @@ static void harvest_vpa_dirty(struct kvmppc_vpa *vpa,
|
||||
__set_bit_le(gfn - memslot->base_gfn, map);
|
||||
}
|
||||
|
||||
long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
unsigned long *map)
|
||||
long kvmppc_hv_get_dirty_log_hpt(struct kvm *kvm,
|
||||
struct kvm_memory_slot *memslot, unsigned long *map)
|
||||
{
|
||||
unsigned long i, j;
|
||||
unsigned long *rmapp;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
preempt_disable();
|
||||
rmapp = memslot->arch.rmap;
|
||||
@@ -1079,15 +1105,6 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
||||
__set_bit_le(j, map);
|
||||
++rmapp;
|
||||
}
|
||||
|
||||
/* Harvest dirty bits from VPA and DTL updates */
|
||||
/* Note: we never modify the SLB shadow buffer areas */
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
spin_lock(&vcpu->arch.vpa_update_lock);
|
||||
harvest_vpa_dirty(&vcpu->arch.vpa, memslot, map);
|
||||
harvest_vpa_dirty(&vcpu->arch.dtl, memslot, map);
|
||||
spin_unlock(&vcpu->arch.vpa_update_lock);
|
||||
}
|
||||
preempt_enable();
|
||||
return 0;
|
||||
}
|
||||
@@ -1142,10 +1159,14 @@ void kvmppc_unpin_guest_page(struct kvm *kvm, void *va, unsigned long gpa,
|
||||
srcu_idx = srcu_read_lock(&kvm->srcu);
|
||||
memslot = gfn_to_memslot(kvm, gfn);
|
||||
if (memslot) {
|
||||
rmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
lock_rmap(rmap);
|
||||
*rmap |= KVMPPC_RMAP_CHANGED;
|
||||
unlock_rmap(rmap);
|
||||
if (!kvm_is_radix(kvm)) {
|
||||
rmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
|
||||
lock_rmap(rmap);
|
||||
*rmap |= KVMPPC_RMAP_CHANGED;
|
||||
unlock_rmap(rmap);
|
||||
} else if (memslot->dirty_bitmap) {
|
||||
mark_page_dirty(kvm, gfn);
|
||||
}
|
||||
}
|
||||
srcu_read_unlock(&kvm->srcu, srcu_idx);
|
||||
}
|
||||
@@ -1675,7 +1696,10 @@ void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu)
|
||||
|
||||
vcpu->arch.slb_nr = 32; /* POWER7/POWER8 */
|
||||
|
||||
mmu->xlate = kvmppc_mmu_book3s_64_hv_xlate;
|
||||
if (kvm_is_radix(vcpu->kvm))
|
||||
mmu->xlate = kvmppc_mmu_radix_xlate;
|
||||
else
|
||||
mmu->xlate = kvmppc_mmu_book3s_64_hv_xlate;
|
||||
mmu->reset_msr = kvmppc_mmu_book3s_64_hv_reset_msr;
|
||||
|
||||
vcpu->arch.hflags |= BOOK3S_HFLAG_SLB;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+181
-24
@@ -1132,7 +1132,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
|
||||
/*
|
||||
* Userspace can only modify DPFD (default prefetch depth),
|
||||
* ILE (interrupt little-endian) and TC (translation control).
|
||||
* On POWER8 userspace can also modify AIL (alt. interrupt loc.)
|
||||
* On POWER8 and POWER9 userspace can also modify AIL (alt. interrupt loc.).
|
||||
*/
|
||||
mask = LPCR_DPFD | LPCR_ILE | LPCR_TC;
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
@@ -1818,6 +1818,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
|
||||
vcpu->arch.vcore = vcore;
|
||||
vcpu->arch.ptid = vcpu->vcpu_id - vcore->first_vcpuid;
|
||||
vcpu->arch.thread_cpu = -1;
|
||||
vcpu->arch.prev_cpu = -1;
|
||||
|
||||
vcpu->arch.cpu_type = KVM_CPU_3S_64;
|
||||
kvmppc_sanity_check(vcpu);
|
||||
@@ -1947,11 +1948,33 @@ static void kvmppc_release_hwthread(int cpu)
|
||||
tpaca->kvm_hstate.kvm_split_mode = NULL;
|
||||
}
|
||||
|
||||
static void do_nothing(void *x)
|
||||
{
|
||||
}
|
||||
|
||||
static void radix_flush_cpu(struct kvm *kvm, int cpu, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
cpu = cpu_first_thread_sibling(cpu);
|
||||
cpumask_set_cpu(cpu, &kvm->arch.need_tlb_flush);
|
||||
/*
|
||||
* Make sure setting of bit in need_tlb_flush precedes
|
||||
* testing of cpu_in_guest bits. The matching barrier on
|
||||
* the other side is the first smp_mb() in kvmppc_run_core().
|
||||
*/
|
||||
smp_mb();
|
||||
for (i = 0; i < threads_per_core; ++i)
|
||||
if (cpumask_test_cpu(cpu + i, &kvm->arch.cpu_in_guest))
|
||||
smp_call_function_single(cpu + i, do_nothing, NULL, 1);
|
||||
}
|
||||
|
||||
static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)
|
||||
{
|
||||
int cpu;
|
||||
struct paca_struct *tpaca;
|
||||
struct kvmppc_vcore *mvc = vc->master_vcore;
|
||||
struct kvm *kvm = vc->kvm;
|
||||
|
||||
cpu = vc->pcpu;
|
||||
if (vcpu) {
|
||||
@@ -1962,6 +1985,27 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc)
|
||||
cpu += vcpu->arch.ptid;
|
||||
vcpu->cpu = mvc->pcpu;
|
||||
vcpu->arch.thread_cpu = cpu;
|
||||
|
||||
/*
|
||||
* With radix, the guest can do TLB invalidations itself,
|
||||
* and it could choose to use the local form (tlbiel) if
|
||||
* it is invalidating a translation that has only ever been
|
||||
* used on one vcpu. However, that doesn't mean it has
|
||||
* only ever been used on one physical cpu, since vcpus
|
||||
* can move around between pcpus. To cope with this, when
|
||||
* a vcpu moves from one pcpu to another, we need to tell
|
||||
* any vcpus running on the same core as this vcpu previously
|
||||
* ran to flush the TLB. The TLB is shared between threads,
|
||||
* so we use a single bit in .need_tlb_flush for all 4 threads.
|
||||
*/
|
||||
if (kvm_is_radix(kvm) && vcpu->arch.prev_cpu != cpu) {
|
||||
if (vcpu->arch.prev_cpu >= 0 &&
|
||||
cpu_first_thread_sibling(vcpu->arch.prev_cpu) !=
|
||||
cpu_first_thread_sibling(cpu))
|
||||
radix_flush_cpu(kvm, vcpu->arch.prev_cpu, vcpu);
|
||||
vcpu->arch.prev_cpu = cpu;
|
||||
}
|
||||
cpumask_set_cpu(cpu, &kvm->arch.cpu_in_guest);
|
||||
}
|
||||
tpaca = &paca[cpu];
|
||||
tpaca->kvm_hstate.kvm_vcpu = vcpu;
|
||||
@@ -2549,6 +2593,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
|
||||
kvmppc_release_hwthread(pcpu + i);
|
||||
if (sip && sip->napped[i])
|
||||
kvmppc_ipi_thread(pcpu + i);
|
||||
cpumask_clear_cpu(pcpu + i, &vc->kvm->arch.cpu_in_guest);
|
||||
}
|
||||
|
||||
kvmppc_set_host_core(pcpu);
|
||||
@@ -2875,7 +2920,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
smp_mb();
|
||||
|
||||
/* On the first time here, set up HTAB and VRMA */
|
||||
if (!vcpu->kvm->arch.hpte_setup_done) {
|
||||
if (!kvm_is_radix(vcpu->kvm) && !vcpu->kvm->arch.hpte_setup_done) {
|
||||
r = kvmppc_hv_setup_htab_rma(vcpu);
|
||||
if (r)
|
||||
goto out;
|
||||
@@ -2937,6 +2982,13 @@ static int kvm_vm_ioctl_get_smmu_info_hv(struct kvm *kvm,
|
||||
{
|
||||
struct kvm_ppc_one_seg_page_size *sps;
|
||||
|
||||
/*
|
||||
* Since we don't yet support HPT guests on a radix host,
|
||||
* return an error if the host uses radix.
|
||||
*/
|
||||
if (radix_enabled())
|
||||
return -EINVAL;
|
||||
|
||||
info->flags = KVM_PPC_PAGE_SIZES_REAL;
|
||||
if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
|
||||
info->flags |= KVM_PPC_1T_SEGMENTS;
|
||||
@@ -2959,8 +3011,10 @@ static int kvm_vm_ioctl_get_dirty_log_hv(struct kvm *kvm,
|
||||
{
|
||||
struct kvm_memslots *slots;
|
||||
struct kvm_memory_slot *memslot;
|
||||
int r;
|
||||
int i, r;
|
||||
unsigned long n;
|
||||
unsigned long *buf;
|
||||
struct kvm_vcpu *vcpu;
|
||||
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
|
||||
@@ -2974,15 +3028,32 @@ static int kvm_vm_ioctl_get_dirty_log_hv(struct kvm *kvm,
|
||||
if (!memslot->dirty_bitmap)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Use second half of bitmap area because radix accumulates
|
||||
* bits in the first half.
|
||||
*/
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
memset(memslot->dirty_bitmap, 0, n);
|
||||
buf = memslot->dirty_bitmap + n / sizeof(long);
|
||||
memset(buf, 0, n);
|
||||
|
||||
r = kvmppc_hv_get_dirty_log(kvm, memslot, memslot->dirty_bitmap);
|
||||
if (kvm_is_radix(kvm))
|
||||
r = kvmppc_hv_get_dirty_log_radix(kvm, memslot, buf);
|
||||
else
|
||||
r = kvmppc_hv_get_dirty_log_hpt(kvm, memslot, buf);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
/* Harvest dirty bits from VPA and DTL updates */
|
||||
/* Note: we never modify the SLB shadow buffer areas */
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
spin_lock(&vcpu->arch.vpa_update_lock);
|
||||
kvmppc_harvest_vpa_dirty(&vcpu->arch.vpa, memslot, buf);
|
||||
kvmppc_harvest_vpa_dirty(&vcpu->arch.dtl, memslot, buf);
|
||||
spin_unlock(&vcpu->arch.vpa_update_lock);
|
||||
}
|
||||
|
||||
r = -EFAULT;
|
||||
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
|
||||
if (copy_to_user(log->dirty_bitmap, buf, n))
|
||||
goto out;
|
||||
|
||||
r = 0;
|
||||
@@ -3003,6 +3074,15 @@ static void kvmppc_core_free_memslot_hv(struct kvm_memory_slot *free,
|
||||
static int kvmppc_core_create_memslot_hv(struct kvm_memory_slot *slot,
|
||||
unsigned long npages)
|
||||
{
|
||||
/*
|
||||
* For now, if radix_enabled() then we only support radix guests,
|
||||
* and in that case we don't need the rmap array.
|
||||
*/
|
||||
if (radix_enabled()) {
|
||||
slot->arch.rmap = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
|
||||
if (!slot->arch.rmap)
|
||||
return -ENOMEM;
|
||||
@@ -3035,7 +3115,7 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
|
||||
if (npages)
|
||||
atomic64_inc(&kvm->arch.mmio_update);
|
||||
|
||||
if (npages && old->npages) {
|
||||
if (npages && old->npages && !kvm_is_radix(kvm)) {
|
||||
/*
|
||||
* If modifying a memslot, reset all the rmap dirty bits.
|
||||
* If this is a new memslot, we don't need to do anything
|
||||
@@ -3044,7 +3124,7 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
|
||||
*/
|
||||
slots = kvm_memslots(kvm);
|
||||
memslot = id_to_memslot(slots, mem->slot);
|
||||
kvmppc_hv_get_dirty_log(kvm, memslot, NULL);
|
||||
kvmppc_hv_get_dirty_log_hpt(kvm, memslot, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3083,14 +3163,20 @@ static void kvmppc_setup_partition_table(struct kvm *kvm)
|
||||
{
|
||||
unsigned long dw0, dw1;
|
||||
|
||||
/* PS field - page size for VRMA */
|
||||
dw0 = ((kvm->arch.vrma_slb_v & SLB_VSID_L) >> 1) |
|
||||
((kvm->arch.vrma_slb_v & SLB_VSID_LP) << 1);
|
||||
/* HTABSIZE and HTABORG fields */
|
||||
dw0 |= kvm->arch.sdr1;
|
||||
if (!kvm_is_radix(kvm)) {
|
||||
/* PS field - page size for VRMA */
|
||||
dw0 = ((kvm->arch.vrma_slb_v & SLB_VSID_L) >> 1) |
|
||||
((kvm->arch.vrma_slb_v & SLB_VSID_LP) << 1);
|
||||
/* HTABSIZE and HTABORG fields */
|
||||
dw0 |= kvm->arch.sdr1;
|
||||
|
||||
/* Second dword has GR=0; other fields are unused since UPRT=0 */
|
||||
dw1 = 0;
|
||||
/* Second dword as set by userspace */
|
||||
dw1 = kvm->arch.process_table;
|
||||
} else {
|
||||
dw0 = PATB_HR | radix__get_tree_size() |
|
||||
__pa(kvm->arch.pgtable) | RADIX_PGD_INDEX_SIZE;
|
||||
dw1 = PATB_GR | kvm->arch.process_table;
|
||||
}
|
||||
|
||||
mmu_partition_table_set_entry(kvm->arch.lpid, dw0, dw1);
|
||||
}
|
||||
@@ -3260,6 +3346,7 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
|
||||
{
|
||||
unsigned long lpcr, lpid;
|
||||
char buf[32];
|
||||
int ret;
|
||||
|
||||
/* Allocate the guest's logical partition ID */
|
||||
|
||||
@@ -3307,13 +3394,30 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
|
||||
lpcr |= LPCR_HVICE;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, if the host uses radix, the guest must be radix.
|
||||
*/
|
||||
if (radix_enabled()) {
|
||||
kvm->arch.radix = 1;
|
||||
lpcr &= ~LPCR_VPM1;
|
||||
lpcr |= LPCR_UPRT | LPCR_GTSE | LPCR_HR;
|
||||
ret = kvmppc_init_vm_radix(kvm);
|
||||
if (ret) {
|
||||
kvmppc_free_lpid(kvm->arch.lpid);
|
||||
return ret;
|
||||
}
|
||||
kvmppc_setup_partition_table(kvm);
|
||||
}
|
||||
|
||||
kvm->arch.lpcr = lpcr;
|
||||
|
||||
/*
|
||||
* Work out how many sets the TLB has, for the use of
|
||||
* the TLB invalidation loop in book3s_hv_rmhandlers.S.
|
||||
*/
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
if (kvm_is_radix(kvm))
|
||||
kvm->arch.tlb_sets = POWER9_TLB_SETS_RADIX; /* 128 */
|
||||
else if (cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
kvm->arch.tlb_sets = POWER9_TLB_SETS_HASH; /* 256 */
|
||||
else if (cpu_has_feature(CPU_FTR_ARCH_207S))
|
||||
kvm->arch.tlb_sets = POWER8_TLB_SETS; /* 512 */
|
||||
@@ -3323,8 +3427,11 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
|
||||
/*
|
||||
* Track that we now have a HV mode VM active. This blocks secondary
|
||||
* CPU threads from coming online.
|
||||
* On POWER9, we only need to do this for HPT guests on a radix
|
||||
* host, which is not yet supported.
|
||||
*/
|
||||
kvm_hv_vm_activated();
|
||||
if (!cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
kvm_hv_vm_activated();
|
||||
|
||||
/*
|
||||
* Create a debugfs directory for the VM
|
||||
@@ -3350,11 +3457,17 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
|
||||
{
|
||||
debugfs_remove_recursive(kvm->arch.debugfs_dir);
|
||||
|
||||
kvm_hv_vm_deactivated();
|
||||
if (!cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
kvm_hv_vm_deactivated();
|
||||
|
||||
kvmppc_free_vcores(kvm);
|
||||
|
||||
kvmppc_free_hpt(kvm);
|
||||
kvmppc_free_lpid(kvm->arch.lpid);
|
||||
|
||||
if (kvm_is_radix(kvm))
|
||||
kvmppc_free_radix(kvm);
|
||||
else
|
||||
kvmppc_free_hpt(kvm);
|
||||
|
||||
kvmppc_free_pimap(kvm);
|
||||
}
|
||||
@@ -3383,11 +3496,6 @@ static int kvmppc_core_check_processor_compat_hv(void)
|
||||
if (!cpu_has_feature(CPU_FTR_HVMODE) ||
|
||||
!cpu_has_feature(CPU_FTR_ARCH_206))
|
||||
return -EIO;
|
||||
/*
|
||||
* Disable KVM for Power9 in radix mode.
|
||||
*/
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300) && radix_enabled())
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3655,6 +3763,41 @@ static void init_default_hcalls(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int kvmhv_configure_mmu(struct kvm *kvm, struct kvm_ppc_mmuv3_cfg *cfg)
|
||||
{
|
||||
unsigned long lpcr;
|
||||
int radix;
|
||||
|
||||
/* If not on a POWER9, reject it */
|
||||
if (!cpu_has_feature(CPU_FTR_ARCH_300))
|
||||
return -ENODEV;
|
||||
|
||||
/* If any unknown flags set, reject it */
|
||||
if (cfg->flags & ~(KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE))
|
||||
return -EINVAL;
|
||||
|
||||
/* We can't change a guest to/from radix yet */
|
||||
radix = !!(cfg->flags & KVM_PPC_MMUV3_RADIX);
|
||||
if (radix != kvm_is_radix(kvm))
|
||||
return -EINVAL;
|
||||
|
||||
/* GR (guest radix) bit in process_table field must match */
|
||||
if (!!(cfg->process_table & PATB_GR) != radix)
|
||||
return -EINVAL;
|
||||
|
||||
/* Process table size field must be reasonable, i.e. <= 24 */
|
||||
if ((cfg->process_table & PRTS_MASK) > 24)
|
||||
return -EINVAL;
|
||||
|
||||
kvm->arch.process_table = cfg->process_table;
|
||||
kvmppc_setup_partition_table(kvm);
|
||||
|
||||
lpcr = (cfg->flags & KVM_PPC_MMUV3_GTSE) ? LPCR_GTSE : 0;
|
||||
kvmppc_update_lpcr(kvm, lpcr, LPCR_GTSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -3692,6 +3835,8 @@ static struct kvmppc_ops kvm_ops_hv = {
|
||||
.irq_bypass_add_producer = kvmppc_irq_bypass_add_producer_hv,
|
||||
.irq_bypass_del_producer = kvmppc_irq_bypass_del_producer_hv,
|
||||
#endif
|
||||
.configure_mmu = kvmhv_configure_mmu,
|
||||
.get_rmmu_info = kvmhv_get_rmmu_info,
|
||||
};
|
||||
|
||||
static int kvm_init_subcore_bitmap(void)
|
||||
@@ -3726,6 +3871,11 @@ static int kvm_init_subcore_bitmap(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvmppc_radix_possible(void)
|
||||
{
|
||||
return cpu_has_feature(CPU_FTR_ARCH_300) && radix_enabled();
|
||||
}
|
||||
|
||||
static int kvmppc_book3s_init_hv(void)
|
||||
{
|
||||
int r;
|
||||
@@ -3765,12 +3915,19 @@ static int kvmppc_book3s_init_hv(void)
|
||||
init_vcore_lists();
|
||||
|
||||
r = kvmppc_mmu_hv_init();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (kvmppc_radix_possible())
|
||||
r = kvmppc_radix_init();
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvmppc_book3s_exit_hv(void)
|
||||
{
|
||||
kvmppc_free_host_rm_ops();
|
||||
if (kvmppc_radix_possible())
|
||||
kvmppc_radix_exit();
|
||||
kvmppc_hv_ops = NULL;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user