Commit 8f65d678 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Finished arch-dep ept code.

lcd_arch_epte_t type for arch abstraction.

lcd_arch_ept_walk
-- simple lookup of ept entry
-- optionally allocate ept data structures
   along the way

lcd_arch_ept_set
-- set the host physical address in the
   (final level) ept entry, along with
   default flags

lcd_arch_ept_hpa
-- returns host physical address stored in
   an ept entry

Remaining old code will be put in arch-indep
code.
parent 617bbcec
......@@ -40,6 +40,9 @@ enum lcd_arch_reg {
#define LCD_ARCH_FS_SELECTOR 2
#define LCD_ARCH_GS_SELECTOR 3
#define LCD_ARCH_EPT_WALK_LENGTH 4
#define LCD_ARCH_EPTP_WALK_SHIFT 3
struct lcd_arch_ept {
spinlock_t lock;
unsigned long root_hpa;
......@@ -47,6 +50,9 @@ struct lcd_arch_ept {
bool access_dirty_enabled;
};
typedef epte_t lcd_arch_epte_t;
struct lcd_arch {
/*
* Public Data
......@@ -133,4 +139,22 @@ enum lcd_arch_status {
LCD_ARCH_STATUS_CR3_ACCESS = 3,
};
/**
* Lookup ept entry for guest physical address gpa.
*
* Set create = 1 to allocate ept page table data structures
* along the path as needed.
*/
int lcd_arch_ept_walk(struct lcd_arch *vcpu, u64 gpa, int create,
lcd_arch_epte_t **epte_out);
/**
* Set the guest physical => host physical mapping in the ept entry.
*/
int lcd_arch_ept_set(lcd_arch_epte_t *epte, u64 hpa);
/**
* Read the host physical address stored in epte.
*/
u64 lcd_arch_ept_hpa(lcd_arch_epte_t *epte);
#endif /* LCD_DOMAINS_ARCH_H */
......@@ -873,6 +873,109 @@ void lcd_arch_exit(void)
/* VMX EPT -------------------------------------------------- */
/**
* PAGE_SHIFT is assumed to be 12.
*/
#define VMX_EPTE_ADDR_MASK PAGE_MASK
#define VMX_EPTE_ADDR(epte) (((u64)epte) & PAGE_MASK)
#define VMX_EPT_ALL_MASK (VMX_EPT_READABLE_MASK | \
VMX_EPT_WRITABLE_MASK | \
VMX_EPT_EXECUTABLE_MASK)
#define VMX_EPTE_PRESENT(epte) (epte & VMX_EPT_ALL_MASK)
enum vmx_epte_mts {
VMX_EPTE_MT_UC = 0, /* uncachable */
VMX_EPTE_MT_WC = 1, /* write combining */
VMX_EPTE_MT_WT = 4, /* write through */
VMX_EPTE_MT_WP = 5, /* write protected */
VMX_EPTE_MT_WB = 6, /* write back */
};
/**
* Sets address in epte along with default access settings. Since
* we are using a page walk length of 4, epte's at all levels have
* the `size' bit (bit 7) set to 0. Page table entries (entries at the final
* level) have the IPAT (ignore page attribute table) and EPT MT (memory
* type) bits set. See Intel SDM V3 Figure 28-1 and 28.2.2.
*/
static void vmx_epte_set(lcd_arch_epte_t *epte, u64 hpa, int level)
{
/*
* zero out epte, and set
*/
*epte = 0;
*epte = (hpa & VMX_EPTE_ADDR_MASK) | VMX_EPT_ALL_MASK;
if (level == 3) {
/*
* Page table entry. Set EPT memory type to write back
* and ignore page attribute table.
*/
*epte |= (VMX_EPT_IPAT_BIT |
(VMX_EPTE_MT_WB << VMX_EPT_MT_EPTE_SHIFT));
}
}
int lcd_arch_ept_walk(struct lcd_arch *vcpu, u64 gpa, int create,
lcd_arch_epte_t **epte_out)
{
int i;
epte_t *dir;
u64 mask;
u64 idx;
u64 page;
dir = (lcd_arch_epte_t *) __va(vcpu->ept.root_hpa);
/*
* The first level uses bits 47:39 (9 bits) of the gpa
*/
mask = 0x1ff << 39;
/*
* Walk plm4 -> pdpt -> pd. Each step uses 9 bits
* of the gpa.
*/
for (i = 0; i < LCD_ARCH_EPT_WALK_LENGTH - 1; i++) {
idx = gpa & mask;
if (!epte_present(dir[idx])) {
if (!create)
return -ENOENT;
/*
* Get host virtual addr of fresh page, and
* set the epte's addr to the host physical addr
*/
page = __get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
memset((void *)page, 0, PAGE_SIZE);
vmx_epte_set(dir[idx], __pa(page), i);
}
dir = (epte_t *) __va(VMX_EPTE_ADDR(dir[idx]));
mask >>= 9;
}
/*
* mask is now 0x1ff000, and dir points to the correct page
* table.
*/
*epte_out = &dir[gpa & mask];
return 0;
}
void lcd_arch_ept_set(lcd_arch_epte_t *epte, u64 hpa)
{
vmx_epte_set(epte, hpa, 3);
}
u64 lcd_arch_ept_hpa(lcd_arch_epte_t *epte)
{
return VMX_EPTE_ADDR(*epte);
}
/**
* Initializes the EPT's root global page directory page, the
* VMCS pointer, and the spinlock.
......@@ -905,7 +1008,7 @@ int vmx_init_ept(struct lcd_arch *vcpu)
*/
eptp = VMX_EPT_DEFAULT_MT |
VMX_EPT_DEFAULT_GAW << VMX_EPT_GAW_EPTP_SHIFT;
(LCD_ARCH_EPT_WALK_LENGTH - 1) << LCD_ARCH_EPTP_WALK_SHIFT;
if (cpu_has_vmx_ept_ad_bits()) {
vcpu->ept.access_dirty_enabled = true;
eptp |= VMX_EPT_AD_ENABLE_BIT;
......@@ -2012,7 +2115,6 @@ int lcd_arch_run(struct lcd_arch *vcpu)
return ret;
}
/* EXPORTS -------------------------------------------------- */
EXPORT_SYMBOL(lcd_arch_init);
......@@ -2020,3 +2122,7 @@ EXPORT_SYMBOL(lcd_arch_exit);
EXPORT_SYMBOL(lcd_arch_create);
EXPORT_SYMBOL(lcd_arch_destroy);
EXPORT_SYMBOL(lcd_arch_run);
EXPORT_SYMBOL(lcd_arch_ept_walk);
EXPORT_SYMBOL(lcd_arch_ept_set);
EXPORT_SYMBOL(lcd_arch_ept_hpa);
......@@ -269,38 +269,38 @@
/* vmcs_writel(field, value); */
/* } */
static inline bool is_external_interrupt(u32 intr_info) {
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
/* static inline bool is_external_interrupt(u32 intr_info) { */
/* return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) */
/* == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); */
/* } */
/* Memory Management */
static inline bool is_page_fault(u32 intr_info) {
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
INTR_INFO_VALID_MASK)) ==
(INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
}
/* static inline bool is_page_fault(u32 intr_info) { */
/* return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | */
/* INTR_INFO_VALID_MASK)) == */
/* (INTR_TYPE_HARD_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); */
/* } */
static inline uintptr_t epte_addr(epte_t epte) {
return (epte & EPTE_ADDR);
}
/* static inline uintptr_t epte_addr(epte_t epte) { */
/* return (epte & EPTE_ADDR); */
/* } */
static inline uintptr_t epte_page_vaddr(epte_t epte) {
return (uintptr_t) __va(epte_addr(epte));
}
/* static inline uintptr_t epte_page_vaddr(epte_t epte) { */
/* return (uintptr_t) __va(epte_addr(epte)); */
/* } */
static inline epte_t epte_flags(epte_t epte) {
return (epte & EPTE_FLAGS);
}
/* static inline epte_t epte_flags(epte_t epte) { */
/* return (epte & EPTE_FLAGS); */
/* } */
static inline int epte_present(epte_t epte) {
return (epte & __EPTE_FULL) > 0;
}
/* static inline int epte_present(epte_t epte) { */
/* return (epte & __EPTE_FULL) > 0; */
/* } */
static inline int epte_big(epte_t epte) {
return (epte & __EPTE_SZ) > 0;
}
/* static inline int epte_big(epte_t epte) { */
/* return (epte & __EPTE_SZ) > 0; */
/* } */
static void free_ept_page(epte_t epte) {
struct page *page = pfn_to_page(epte_addr(epte) >> PAGE_SHIFT);
......@@ -320,75 +320,75 @@ static int clear_epte(epte_t *epte) {
return 1;
}
/**
* Look up the ept entry for guest physical
* address gpa. If create is 1, ept paging structures
* will be allocated on the fly.
*
* The page frame where gpa resides is not allocated.
*
* FIXME: Do we need to lock inside here?
*/
static int lcd_ept_walk(struct lcd *vcpu, u64 gpa, int create,
epte_t **epte_out) {
int i;
epte_t *dir = (epte_t *) __va(vcpu->ept_root);
/* /\** */
/* * Look up the ept entry for guest physical */
/* * address gpa. If create is 1, ept paging structures */
/* * will be allocated on the fly. */
/* * */
/* * The page frame where gpa resides is not allocated. */
/* * */
/* * FIXME: Do we need to lock inside here? */
/* *\/ */
/* static int lcd_ept_walk(struct lcd *vcpu, u64 gpa, int create, */
/* epte_t **epte_out) { */
/* int i; */
/* epte_t *dir = (epte_t *) __va(vcpu->ept_root); */
for (i = EPT_LEVELS - 1; i > 0; i--) {
int idx = ADDR_TO_IDX(gpa, i);
/* for (i = EPT_LEVELS - 1; i > 0; i--) { */
/* int idx = ADDR_TO_IDX(gpa, i); */
if (!epte_present(dir[idx])) {
void *page;
/* if (!epte_present(dir[idx])) { */
/* void *page; */
if (!create)
return -ENOENT;
/* if (!create) */
/* return -ENOENT; */
page = (void *) __get_free_page(GFP_ATOMIC);
if (!page)
return -ENOMEM;
/* page = (void *) __get_free_page(GFP_ATOMIC); */
/* if (!page) */
/* return -ENOMEM; */
memset(page, 0, PAGE_SIZE);
dir[idx] = epte_addr(virt_to_phys(page)) |
__EPTE_FULL;
}
/* memset(page, 0, PAGE_SIZE); */
/* dir[idx] = epte_addr(virt_to_phys(page)) | */
/* __EPTE_FULL; */
/* } */
if (epte_big(dir[idx])) {
return -EINVAL;
}
/* if (epte_big(dir[idx])) { */
/* return -EINVAL; */
/* } */
dir = (epte_t *) epte_page_vaddr(dir[idx]);
}
/* dir = (epte_t *) epte_page_vaddr(dir[idx]); */
/* } */
*epte_out = &dir[ADDR_TO_IDX(gpa, 0)];
return 0;
}
/* *epte_out = &dir[ADDR_TO_IDX(gpa, 0)]; */
/* return 0; */
/* } */
/**
* Store host physical address hpa, along with
* default flags, to the epte.
*
* FIXME: Do we want to lock inside here?
*/
static int lcd_ept_set_epte(struct lcd *vcpu, epte_t *epte_entry, u64 hpa) {
int ret;
epte_t flags;
/* /\** */
/* * Store host physical address hpa, along with */
/* * default flags, to the epte. */
/* * */
/* * FIXME: Do we want to lock inside here? */
/* *\/ */
/* static int lcd_ept_set_epte(struct lcd *vcpu, epte_t *epte_entry, u64 hpa) { */
/* int ret; */
/* epte_t flags; */
spin_lock(&vcpu->ept_lock);
/* spin_lock(&vcpu->ept_lock); */
flags = __EPTE_READ | __EPTE_EXEC | __EPTE_WRITE |
__EPTE_TYPE(EPTE_TYPE_WB) | __EPTE_IPAT;
/* flags = __EPTE_READ | __EPTE_EXEC | __EPTE_WRITE | */
/* __EPTE_TYPE(EPTE_TYPE_WB) | __EPTE_IPAT; */
if (vcpu->ept_ad_enabled) {
/* premark A/D to avoid extra memory references */
flags |= __EPTE_A | __EPTE_D;
}
/* if (vcpu->ept_ad_enabled) { */
/* /\* premark A/D to avoid extra memory references *\/ */
/* flags |= __EPTE_A | __EPTE_D; */
/* } */
*epte = epte_addr(hpa) | flags;
/* *epte = epte_addr(hpa) | flags; */
spin_unlock(&vcpu->ept_lock);
/* spin_unlock(&vcpu->ept_lock); */
return 0;
}
/* return 0; */
/* } */
/**
* Maps gpa to hpa in the lcd's ept. Simple wrapper
......@@ -497,29 +497,29 @@ static void lcd_free_ept(u64 ept_root) {
}
int vmx_init_ept(struct lcd *vcpu) {
void *page = (void *) __get_free_page(GFP_KERNEL);
/* int vmx_init_ept(struct lcd *vcpu) { */
/* void *page = (void *) __get_free_page(GFP_KERNEL); */
if (!page)
return -ENOMEM;
/* if (!page) */
/* return -ENOMEM; */
memset(page, 0, PAGE_SIZE);
vcpu->ept_root = __pa(page);
/* memset(page, 0, PAGE_SIZE); */
/* vcpu->ept_root = __pa(page); */
return 0;
}
/* return 0; */
/* } */
static u64 construct_eptp(u64 root_hpa) {
u64 eptp;
/* static u64 construct_eptp(u64 root_hpa) { */
/* u64 eptp; */
eptp = VMX_EPT_DEFAULT_MT |
VMX_EPT_DEFAULT_GAW << VMX_EPT_GAW_EPTP_SHIFT;
if (cpu_has_vmx_ept_ad_bits())
eptp |= VMX_EPT_AD_ENABLE_BIT;
eptp |= (root_hpa & PAGE_MASK);
/* eptp = VMX_EPT_DEFAULT_MT | */
/* VMX_EPT_DEFAULT_GAW << VMX_EPT_GAW_EPTP_SHIFT; */
/* if (cpu_has_vmx_ept_ad_bits()) */
/* eptp |= VMX_EPT_AD_ENABLE_BIT; */
/* eptp |= (root_hpa & PAGE_MASK); */
return eptp;
}
/* return eptp; */
/* } */
/* END EPT ======================================== */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment