Commit 04262816 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

x86: vm: export get_pte and return a pointer to it



This lets us modify the flags for the PTE corresponding to a virtual address.
The SMAP testcase will use this to build supervisor-mode pages.

Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 0a5701ed
......@@ -54,11 +54,11 @@ static unsigned long end_of_memory;
#define PGDIR_MASK 1023
#endif
void install_pte(unsigned long *cr3,
int pte_level,
void *virt,
unsigned long pte,
unsigned long *pt_page)
unsigned long *install_pte(unsigned long *cr3,
int pte_level,
void *virt,
unsigned long pte,
unsigned long *pt_page)
{
int level;
unsigned long *pt = cr3;
......@@ -79,9 +79,10 @@ void install_pte(unsigned long *cr3,
}
offset = ((unsigned long)virt >> ((level-1) * PGDIR_WIDTH + 12)) & PGDIR_MASK;
pt[offset] = pte;
return &pt[offset];
}
static unsigned long get_pte(unsigned long *cr3, void *virt)
unsigned long *get_pte(unsigned long *cr3, void *virt)
{
int level;
unsigned long *pt = cr3, pte;
......@@ -91,28 +92,28 @@ static unsigned long get_pte(unsigned long *cr3, void *virt)
offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
pte = pt[offset];
if (!(pte & PTE_PRESENT))
return 0;
return NULL;
if (level == 2 && (pte & PTE_PSE))
return pte;
return &pt[offset];
pt = phys_to_virt(pte & 0xffffffffff000ull);
}
offset = ((unsigned long)virt >> (((level-1) * PGDIR_WIDTH) + 12)) & PGDIR_MASK;
pte = pt[offset];
return pte;
return &pt[offset];
}
void install_large_page(unsigned long *cr3,
unsigned long phys,
void *virt)
unsigned long *install_large_page(unsigned long *cr3,
unsigned long phys,
void *virt)
{
install_pte(cr3, 2, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER | PTE_PSE, 0);
return install_pte(cr3, 2, virt,
phys | PTE_PRESENT | PTE_WRITE | PTE_USER | PTE_PSE, 0);
}
void install_page(unsigned long *cr3,
unsigned long phys,
void *virt)
unsigned long *install_page(unsigned long *cr3,
unsigned long phys,
void *virt)
{
install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER, 0);
return install_pte(cr3, 1, virt, phys | PTE_PRESENT | PTE_WRITE | PTE_USER, 0);
}
......@@ -194,7 +195,7 @@ void *vmalloc(unsigned long size)
uint64_t virt_to_phys_cr3(void *mem)
{
return (get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR) + ((ulong)mem & (PAGE_SIZE - 1));
return (*get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR) + ((ulong)mem & (PAGE_SIZE - 1));
}
void vfree(void *mem)
......@@ -202,7 +203,7 @@ void vfree(void *mem)
unsigned long size = ((unsigned long *)mem)[-1];
while (size) {
free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
free_page(phys_to_virt(*get_pte(phys_to_virt(read_cr3()), mem) & PTE_ADDR));
mem += PAGE_SIZE;
size -= PAGE_SIZE;
}
......
......@@ -25,17 +25,18 @@ void *alloc_vpage(void);
void *alloc_vpages(ulong nr);
uint64_t virt_to_phys_cr3(void *mem);
void install_pte(unsigned long *cr3,
int pte_level,
void *virt,
unsigned long pte,
unsigned long *pt_page);
unsigned long *get_pte(unsigned long *cr3, void *virt);
unsigned long *install_pte(unsigned long *cr3,
int pte_level,
void *virt,
unsigned long pte,
unsigned long *pt_page);
void *alloc_page();
void install_large_page(unsigned long *cr3,unsigned long phys,
void *virt);
void install_page(unsigned long *cr3, unsigned long phys, void *virt);
unsigned long *install_large_page(unsigned long *cr3,unsigned long phys,
void *virt);
unsigned long *install_page(unsigned long *cr3, unsigned long phys, void *virt);
static inline unsigned long virt_to_phys(const void *virt)
{
......
Supports Markdown
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