Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8ff7b956 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-s390-next-4.8-2' of...

Merge tag 'kvm-s390-next-4.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD

KVM: s390: vSIE (nested virtualization) feature for 4.8 (kvm/next)

With an updated QEMU this allows to create nested KVM guests
(KVM under KVM) on s390.

s390 memory management changes from Martin Schwidefsky or
acked by Martin. One common code memory management change (pageref)
acked by Andrew Morton.

The feature has to be enabled with the nested medule parameter.
parents 64672c95 a411edf1
Loading
Loading
Loading
Loading
+76 −6
Original line number Diff line number Diff line
@@ -10,14 +10,25 @@

/**
 * struct gmap_struct - guest address space
 * @list: list head for the mm->context gmap list
 * @crst_list: list of all crst tables used in the guest address space
 * @mm: pointer to the parent mm_struct
 * @guest_to_host: radix tree with guest to host address translation
 * @host_to_guest: radix tree with pointer to segment table entries
 * @guest_table_lock: spinlock to protect all entries in the guest page table
 * @ref_count: reference counter for the gmap structure
 * @table: pointer to the page directory
 * @asce: address space control element for gmap page table
 * @pfault_enabled: defines if pfaults are applicable for the guest
 * @host_to_rmap: radix tree with gmap_rmap lists
 * @children: list of shadow gmap structures
 * @pt_list: list of all page tables used in the shadow guest address space
 * @shadow_lock: spinlock to protect the shadow gmap list
 * @parent: pointer to the parent gmap for shadow guest address spaces
 * @orig_asce: ASCE for which the shadow page table has been created
 * @edat_level: edat level to be used for the shadow translation
 * @removed: flag to indicate if a shadow guest address space has been removed
 * @initialized: flag to indicate if a shadow guest address space can be used
 */
struct gmap {
	struct list_head list;
@@ -26,26 +37,64 @@ struct gmap {
	struct radix_tree_root guest_to_host;
	struct radix_tree_root host_to_guest;
	spinlock_t guest_table_lock;
	atomic_t ref_count;
	unsigned long *table;
	unsigned long asce;
	unsigned long asce_end;
	void *private;
	bool pfault_enabled;
	/* Additional data for shadow guest address spaces */
	struct radix_tree_root host_to_rmap;
	struct list_head children;
	struct list_head pt_list;
	spinlock_t shadow_lock;
	struct gmap *parent;
	unsigned long orig_asce;
	int edat_level;
	bool removed;
	bool initialized;
};

/**
 * struct gmap_rmap - reverse mapping for shadow page table entries
 * @next: pointer to next rmap in the list
 * @raddr: virtual rmap address in the shadow guest address space
 */
struct gmap_rmap {
	struct gmap_rmap *next;
	unsigned long raddr;
};

#define gmap_for_each_rmap(pos, head) \
	for (pos = (head); pos; pos = pos->next)

#define gmap_for_each_rmap_safe(pos, n, head) \
	for (pos = (head); n = pos ? pos->next : NULL, pos; pos = n)

/**
 * struct gmap_notifier - notify function block for page invalidation
 * @notifier_call: address of callback function
 */
struct gmap_notifier {
	struct list_head list;
	void (*notifier_call)(struct gmap *gmap, unsigned long gaddr);
	struct rcu_head rcu;
	void (*notifier_call)(struct gmap *gmap, unsigned long start,
			      unsigned long end);
};

struct gmap *gmap_alloc(struct mm_struct *mm, unsigned long limit);
void gmap_free(struct gmap *gmap);
static inline int gmap_is_shadow(struct gmap *gmap)
{
	return !!gmap->parent;
}

struct gmap *gmap_create(struct mm_struct *mm, unsigned long limit);
void gmap_remove(struct gmap *gmap);
struct gmap *gmap_get(struct gmap *gmap);
void gmap_put(struct gmap *gmap);

void gmap_enable(struct gmap *gmap);
void gmap_disable(struct gmap *gmap);
struct gmap *gmap_get_enabled(void);
int gmap_map_segment(struct gmap *gmap, unsigned long from,
		     unsigned long to, unsigned long len);
int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
@@ -57,8 +106,29 @@ void gmap_discard(struct gmap *, unsigned long from, unsigned long to);
void __gmap_zap(struct gmap *, unsigned long gaddr);
void gmap_unlink(struct mm_struct *, unsigned long *table, unsigned long vmaddr);

void gmap_register_ipte_notifier(struct gmap_notifier *);
void gmap_unregister_ipte_notifier(struct gmap_notifier *);
int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val);

struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce,
			 int edat_level);
int gmap_shadow_valid(struct gmap *sg, unsigned long asce, int edat_level);
int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,
		    int fake);
int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,
		    int fake);
int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,
		    int fake);
int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,
		    int fake);
int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
			   unsigned long *pgt, int *dat_protection, int *fake);
int gmap_shadow_page(struct gmap *sg, unsigned long saddr, pte_t pte);

void gmap_register_pte_notifier(struct gmap_notifier *);
void gmap_unregister_pte_notifier(struct gmap_notifier *);
void gmap_pte_notify(struct mm_struct *, unsigned long addr, pte_t *,
		     unsigned long bits);

int gmap_mprotect_notify(struct gmap *, unsigned long start,
			 unsigned long len, int prot);

#endif /* _ASM_S390_GMAP_H */
+19 −2
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ struct kvm_s390_sie_block {
	__u64	cputm;			/* 0x0028 */
	__u64	ckc;			/* 0x0030 */
	__u64	epoch;			/* 0x0038 */
	__u8	reserved40[4];		/* 0x0040 */
	__u32	svcc;			/* 0x0040 */
#define LCTL_CR0	0x8000
#define LCTL_CR6	0x0200
#define LCTL_CR9	0x0040
@@ -167,6 +167,9 @@ struct kvm_s390_sie_block {
#define ICPT_INST	0x04
#define ICPT_PROGI	0x08
#define ICPT_INSTPROGI	0x0C
#define ICPT_EXTINT	0x14
#define ICPT_VALIDITY	0x20
#define ICPT_STOP	0x28
#define ICPT_OPEREXC	0x2C
#define ICPT_PARTEXEC	0x38
#define ICPT_IOINST	0x40
@@ -226,7 +229,7 @@ struct kvm_s390_sie_block {
	__u8	reserved1e6[2];		/* 0x01e6 */
	__u64	itdba;			/* 0x01e8 */
	__u64   riccbd;			/* 0x01f0 */
	__u8    reserved1f8[8];		/* 0x01f8 */
	__u64	gvrd;			/* 0x01f8 */
} __attribute__((packed));

struct kvm_s390_itdb {
@@ -281,6 +284,7 @@ struct kvm_vcpu_stat {
	u32 instruction_stsi;
	u32 instruction_stfl;
	u32 instruction_tprot;
	u32 instruction_sie;
	u32 instruction_essa;
	u32 instruction_sthyi;
	u32 instruction_sigp_sense;
@@ -545,12 +549,16 @@ struct kvm_guestdbg_info_arch {

struct kvm_vcpu_arch {
	struct kvm_s390_sie_block *sie_block;
	/* if vsie is active, currently executed shadow sie control block */
	struct kvm_s390_sie_block *vsie_block;
	unsigned int      host_acrs[NUM_ACRS];
	struct fpu	  host_fpregs;
	struct kvm_s390_local_interrupt local_int;
	struct hrtimer    ckc_timer;
	struct kvm_s390_pgm_info pgm;
	struct gmap *gmap;
	/* backup location for the currently enabled gmap when scheduled out */
	struct gmap *enabled_gmap;
	struct kvm_guestdbg_info_arch guestdbg;
	unsigned long pfault_token;
	unsigned long pfault_select;
@@ -635,6 +643,14 @@ struct sie_page2 {
	u8 reserved900[0x1000 - 0x900];			/* 0x0900 */
} __packed;

struct kvm_s390_vsie {
	struct mutex mutex;
	struct radix_tree_root addr_to_page;
	int page_count;
	int next;
	struct page *pages[KVM_MAX_VCPUS];
};

struct kvm_arch{
	void *sca;
	int use_esca;
@@ -659,6 +675,7 @@ struct kvm_arch{
	struct sie_page2 *sie_page2;
	struct kvm_s390_cpu_model model;
	struct kvm_s390_crypto crypto;
	struct kvm_s390_vsie vsie;
	u64 epoch;
	/* subset of available cpu features enabled by user space */
	DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
+7 −4
Original line number Diff line number Diff line
@@ -8,8 +8,9 @@ typedef struct {
	cpumask_t cpu_attach_mask;
	atomic_t attach_count;
	unsigned int flush_mm;
	spinlock_t list_lock;
	spinlock_t pgtable_lock;
	struct list_head pgtable_list;
	spinlock_t gmap_lock;
	struct list_head gmap_list;
	unsigned long asce;
	unsigned long asce_limit;
@@ -23,8 +24,10 @@ typedef struct {
} mm_context_t;

#define INIT_MM_CONTEXT(name)						   \
	.context.list_lock    = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
	.context.pgtable_lock =						   \
			__SPIN_LOCK_UNLOCKED(name.context.pgtable_lock),   \
	.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), \
	.context.gmap_lock = __SPIN_LOCK_UNLOCKED(name.context.gmap_lock), \
	.context.gmap_list = LIST_HEAD_INIT(name.context.gmap_list),

static inline int tprot(unsigned long addr)
+2 −1
Original line number Diff line number Diff line
@@ -15,8 +15,9 @@
static inline int init_new_context(struct task_struct *tsk,
				   struct mm_struct *mm)
{
	spin_lock_init(&mm->context.list_lock);
	spin_lock_init(&mm->context.pgtable_lock);
	INIT_LIST_HEAD(&mm->context.pgtable_list);
	spin_lock_init(&mm->context.gmap_lock);
	INIT_LIST_HEAD(&mm->context.gmap_list);
	cpumask_clear(&mm->context.cpu_attach_mask);
	atomic_set(&mm->context.attach_count, 0);
+2 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@ static inline int devmem_is_allowed(unsigned long pfn)
#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define page_to_phys(page)	(page_to_pfn(page) << PAGE_SHIFT)
#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define pfn_to_virt(pfn)	__va((pfn) << PAGE_SHIFT)
#define page_to_virt(page)	pfn_to_virt(page_to_pfn(page))

#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | \
				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
Loading