The final step moves the vmalloc and vmap implementation to generic code, rewriting vmalloc and vfree as an alloc_ops implementation that is installed by setup_vm. This way all architectures can benefit from it just by calling setup_vm and providing the implementation of install_page. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- lib/alloc.c | 5 ++--- lib/alloc.h | 2 -- lib/vmalloc.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/vmalloc.h | 2 ++ lib/x86/asm/page.h | 1 + lib/x86/io.c | 2 +- lib/x86/isr.c | 5 +++-- lib/x86/vm.c | 50 +------------------------------------------------- lib/x86/vm.h | 4 ---- x86/Makefile.common | 1 + x86/asyncpf.c | 4 +++- x86/pmu.c | 4 ++-- x86/sieve.c | 6 +++--- 13 files changed, 72 insertions(+), 67 deletions(-) diff --git a/lib/alloc.c b/lib/alloc.c index 7ce61d2..9e5ae0a 100644 --- a/lib/alloc.c +++ b/lib/alloc.c @@ -1,8 +1,8 @@ #include "alloc.h" +#include "asm/page.h" void *malloc(size_t size) { - size = (size + sizeof(long) - 1) & -sizeof(long); return memalign(sizeof(long), size); } @@ -64,6 +64,5 @@ void *memalign(size_t alignment, size_t size) /* Write the metadata */ *(uintptr_t *)(mem + OFS_SLACK) = slack; *(uintptr_t *)(mem + OFS_SIZE) = size + slack; - return mem; + return (void *)mem; } - diff --git a/lib/alloc.h b/lib/alloc.h index f560c4a..c44d459 100644 --- a/lib/alloc.h +++ b/lib/alloc.h @@ -35,6 +35,4 @@ void *calloc(size_t nmemb, size_t size); void free(void *ptr); void *memalign(size_t alignment, size_t size); -extern struct alloc_ops *alloc_ops; - #endif /* _ALLOC_H_ */ diff --git a/lib/vmalloc.c b/lib/vmalloc.c index c2abe3c..5311b1a 100644 --- a/lib/vmalloc.c +++ b/lib/vmalloc.c @@ -8,6 +8,8 @@ #include "libcflat.h" #include "asm/spinlock.h" #include "asm/page.h" +#include "asm/io.h" +#include "alloc.h" #include "alloc_phys.h" #include "alloc_page.h" @@ -33,6 +35,56 @@ void init_alloc_vpage(void *top) vfree_top = top; } +void *vmap(phys_addr_t phys, size_t size) +{ + void *mem, *p; + unsigned pages; + + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + pages = size / PAGE_SIZE; + mem = p = alloc_vpages(pages); + + phys &= ~(unsigned long long)(PAGE_SIZE - 1); + while (pages--) { + install_page(page_root, phys, p); + phys += PAGE_SIZE; + p += PAGE_SIZE; + } + return mem; +} + +static void *vm_memalign(size_t alignment, size_t size) +{ + void *mem, *p; + unsigned pages; + + assert(alignment <= PAGE_SIZE); + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + pages = size / PAGE_SIZE; + mem = p = alloc_vpages(pages); + while (pages--) { + phys_addr_t pa = virt_to_phys(alloc_page()); + install_page(page_root, pa, p); + p += PAGE_SIZE; + } + return mem; +} + +static void vm_free(void *mem, size_t size) +{ + while (size) { + free_page(phys_to_virt(virt_to_pte_phys(page_root, mem))); + mem += PAGE_SIZE; + size -= PAGE_SIZE; + } +} + +static struct alloc_ops vmalloc_ops = { + .memalign = vm_memalign, + .free = vm_free, + .page_size = PAGE_SIZE, +}; + void setup_vm() { phys_addr_t base, top; @@ -42,4 +94,5 @@ void setup_vm() free_pages((void *)base, top - base); page_root = setup_mmu(top); + alloc_ops = &vmalloc_ops; } diff --git a/lib/vmalloc.h b/lib/vmalloc.h index d4dd880..2a89c33 100644 --- a/lib/vmalloc.h +++ b/lib/vmalloc.h @@ -6,4 +6,6 @@ void *alloc_vpage(void); void init_alloc_vpage(void *top); void setup_vm(); +void *vmap(phys_addr_t phys, size_t size); + #endif diff --git a/lib/x86/asm/page.h b/lib/x86/asm/page.h index 1e6d1a2..1971770 100644 --- a/lib/x86/asm/page.h +++ b/lib/x86/asm/page.h @@ -47,6 +47,7 @@ #define PGDIR_OFFSET(va, lvl) (((va) >> PGDIR_BITS(lvl)) & PGDIR_MASK) extern void *setup_mmu(unsigned long top); +unsigned long *install_page(unsigned long *cr3, phys_addr_t phys, void *virt); phys_addr_t virt_to_pte_phys(void *cr3, void *virt); #endif /* !__ASSEMBLY__ */ diff --git a/lib/x86/io.c b/lib/x86/io.c index cc5ac58..7e1c16d 100644 --- a/lib/x86/io.c +++ b/lib/x86/io.c @@ -1,8 +1,8 @@ #include "libcflat.h" -#include "vm.h" #include "smp.h" #include "asm/io.h" #include "asm/page.h" +#include "vmalloc.h" #ifndef USE_SERIAL #define USE_SERIAL #endif diff --git a/lib/x86/isr.c b/lib/x86/isr.c index 9b1d505..53c0c2b 100644 --- a/lib/x86/isr.c +++ b/lib/x86/isr.c @@ -1,6 +1,7 @@ #include "libcflat.h" +#include "processor.h" #include "isr.h" -#include "vm.h" +#include "alloc.h" #include "desc.h" extern char isr_entry_point[]; @@ -65,7 +66,7 @@ asm ( void handle_irq(unsigned vec, void (*func)(isr_regs_t *regs)) { - u8 *thunk = vmalloc(50); + u8 *thunk = malloc(50); set_idt_entry(vec, thunk, 0); diff --git a/lib/x86/vm.c b/lib/x86/vm.c index 9dd7d79..29aaee3 100644 --- a/lib/x86/vm.c +++ b/lib/x86/vm.c @@ -98,7 +98,7 @@ unsigned long *install_large_page(unsigned long *cr3, } unsigned long *install_page(unsigned long *cr3, - unsigned long phys, + phys_addr_t phys, void *virt) { return install_pte(cr3, 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK | PT_USER_MASK, 0); @@ -179,55 +179,7 @@ void *setup_mmu(unsigned long end_of_memory) return cr3; } -void *vmalloc(unsigned long size) -{ - void *mem, *p; - unsigned pages; - - size += sizeof(unsigned long); - - size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - pages = size / PAGE_SIZE; - mem = p = alloc_vpages(pages); - while (pages--) { - install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p); - p += PAGE_SIZE; - } - *(unsigned long *)mem = size; - mem += sizeof(unsigned long); - return mem; -} - phys_addr_t virt_to_pte_phys(void *cr3, void *mem) { return (*get_pte(cr3, mem) & PT_ADDR_MASK) + ((ulong)mem & (PAGE_SIZE - 1)); } - -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) & PT_ADDR_MASK)); - mem += PAGE_SIZE; - size -= PAGE_SIZE; - } -} - -void *vmap(unsigned long long phys, unsigned long size) -{ - void *mem, *p; - unsigned pages; - - size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); - pages = size / PAGE_SIZE; - mem = p = alloc_vpages(pages); - - phys &= ~(unsigned long long)(PAGE_SIZE - 1); - while (pages--) { - install_page(phys_to_virt(read_cr3()), phys, p); - phys += PAGE_SIZE; - p += PAGE_SIZE; - } - return mem; -} diff --git a/lib/x86/vm.h b/lib/x86/vm.h index 9f668c6..9026293 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -7,10 +7,6 @@ void setup_5level_page_table(); -void *vmalloc(unsigned long size); -void vfree(void *mem); -void *vmap(unsigned long long phys, unsigned long size); - struct pte_search { int level; unsigned long *pte; diff --git a/x86/Makefile.common b/x86/Makefile.common index f0fbadf..5f7eac4 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -4,6 +4,7 @@ all: directories test_cases cflatobjs += lib/pci.o cflatobjs += lib/pci-edu.o +cflatobjs += lib/alloc.o cflatobjs += lib/vmalloc.o cflatobjs += lib/alloc_page.o cflatobjs += lib/alloc_phys.o diff --git a/x86/asyncpf.c b/x86/asyncpf.c index 3b5b4b7..0db5732 100644 --- a/x86/asyncpf.c +++ b/x86/asyncpf.c @@ -22,6 +22,8 @@ #include "x86/isr.h" #include "x86/vm.h" +#include "asm/page.h" +#include "alloc.h" #include "libcflat.h" #include <stdint.h> @@ -94,7 +96,7 @@ int main(int ac, char **av) wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) | KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED); printf("alloc memory\n"); - buf = vmalloc(MEM); + buf = malloc(MEM); irq_enable(); while(loop--) { printf("start loop\n"); diff --git a/x86/pmu.c b/x86/pmu.c index b56b61e..12a5880 100644 --- a/x86/pmu.c +++ b/x86/pmu.c @@ -5,7 +5,7 @@ #include "x86/apic.h" #include "x86/desc.h" #include "x86/isr.h" -#include "x86/vm.h" +#include "alloc.h" #include "libcflat.h" #include <stdint.h> @@ -380,7 +380,7 @@ int main(int ac, char **av) setup_vm(); setup_idt(); handle_irq(PC_VECTOR, cnt_overflow); - buf = vmalloc(N*64); + buf = malloc(N*64); eax.full = id.a; ebx.full = id.b; diff --git a/x86/sieve.c b/x86/sieve.c index 6cbcd6d..2ee2919 100644 --- a/x86/sieve.c +++ b/x86/sieve.c @@ -1,4 +1,4 @@ -#include "vm.h" +#include "alloc.h" #include "libcflat.h" int sieve(char* data, int size) @@ -42,9 +42,9 @@ int main() setup_vm(); test_sieve("mapped", static_data, STATIC_SIZE); for (i = 0; i < 3; ++i) { - v = vmalloc(VSIZE); + v = malloc(VSIZE); test_sieve("virtual", v, VSIZE); - vfree(v); + free(v); } return 0; -- 2.14.2