mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-26 22:24:56 +07:00
0f7f848915
Before any thread is allowed to use a gmap_shadow, it has to be fully initialized. However, for invalidation to work properly, we have to register the new gmap_shadow before we protect the parent gmap table. Because locking is tricky, and we have to avoid duplicate gmaps, let's introduce an initialized field, that signalizes other threads if that gmap_shadow can already be used or if they have to retry. Let's properly return errors using ERR_PTR() instead of simply returning NULL, so a caller can properly react on the error. Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
126 lines
4.6 KiB
C
126 lines
4.6 KiB
C
/*
|
|
* KVM guest address space mapping code
|
|
*
|
|
* Copyright IBM Corp. 2007, 2016
|
|
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
|
*/
|
|
|
|
#ifndef _ASM_S390_GMAP_H
|
|
#define _ASM_S390_GMAP_H
|
|
|
|
/**
|
|
* 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
|
|
* @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;
|
|
struct list_head crst_list;
|
|
struct mm_struct *mm;
|
|
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;
|
|
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;
|
|
struct rcu_head rcu;
|
|
void (*notifier_call)(struct gmap *gmap, unsigned long start,
|
|
unsigned long end);
|
|
};
|
|
|
|
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);
|
|
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);
|
|
unsigned long __gmap_translate(struct gmap *, unsigned long gaddr);
|
|
unsigned long gmap_translate(struct gmap *, unsigned long gaddr);
|
|
int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr);
|
|
int gmap_fault(struct gmap *, unsigned long gaddr, unsigned int fault_flags);
|
|
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);
|
|
|
|
int gmap_read_table(struct gmap *gmap, unsigned long gaddr, unsigned long *val);
|
|
|
|
struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce);
|
|
int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t);
|
|
int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t);
|
|
int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt);
|
|
int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt);
|
|
int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,
|
|
unsigned long *pgt, int *dat_protection);
|
|
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 */
|