This is another step in porting the x86 (v)malloc implementation to other architectures. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- lib/alloc_page.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++ lib/alloc_page.h | 16 +++++++ lib/x86/intel-iommu.c | 2 + lib/x86/intel-iommu.h | 1 - lib/x86/vm.c | 108 +------------------------------------------- lib/x86/vm.h | 4 -- x86/Makefile.common | 1 + x86/emulator.c | 1 + x86/eventinj.c | 3 +- x86/hypercall.c | 1 + x86/hyperv_clock.c | 1 + x86/hyperv_connections.c | 1 + x86/hyperv_stimer.c | 1 + x86/hyperv_synic.c | 1 + x86/intel-iommu.c | 2 + x86/rmap_chain.c | 1 + x86/svm.c | 1 + x86/taskswitch2.c | 1 + x86/vmx.c | 1 + x86/vmx_tests.c | 1 + 20 files changed, 151 insertions(+), 112 deletions(-) create mode 100644 lib/alloc_page.c create mode 100644 lib/alloc_page.h diff --git a/lib/alloc_page.c b/lib/alloc_page.c new file mode 100644 index 0000000..b02dfce --- /dev/null +++ b/lib/alloc_page.c @@ -0,0 +1,115 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2. + * + * This is a simple allocator that provides contiguous physical addresses + * with page granularity. + */ +#include "libcflat.h" +#include <asm/page.h> +#include <asm/io.h> + +static void *free = 0; + +void free_pages(void *mem, unsigned long size) +{ + void *end; + + assert_msg((unsigned long) mem % PAGE_SIZE == 0, + "mem not page aligned: %p", mem); + + assert_msg(size % PAGE_SIZE == 0, "size not page aligned: %#lx", size); + + assert_msg(size == 0 || mem + size > mem, + "mem + size overflow: %p + %#lx", mem, size); + + if (size == 0) { + free = NULL; + return; + } + + free = mem; + end = mem + size; + while (mem + PAGE_SIZE != end) { + *(void **)mem = (mem + PAGE_SIZE); + mem += PAGE_SIZE; + } + + *(void **)mem = NULL; +} + +void *alloc_page() +{ + void *p; + + if (!free) + return 0; + + p = free; + free = *(void **)free; + + return p; +} + +/* + * Allocates (1 << order) physically contiguous and naturally aligned pages. + * Returns NULL if there's no memory left. + */ +void *alloc_pages(unsigned long order) +{ + /* Generic list traversal. */ + void *prev; + void *curr = NULL; + void *next = free; + + /* Looking for a run of length (1 << order). */ + unsigned long run = 0; + const unsigned long n = 1ul << order; + const unsigned long align_mask = (n << PAGE_SHIFT) - 1; + void *run_start = NULL; + void *run_prev = NULL; + unsigned long run_next_pa = 0; + unsigned long pa; + + assert(order < sizeof(unsigned long) * 8); + + for (;;) { + prev = curr; + curr = next; + next = curr ? *((void **) curr) : NULL; + + if (!curr) + return 0; + + pa = virt_to_phys(curr); + + if (run == 0) { + if (!(pa & align_mask)) { + run_start = curr; + run_prev = prev; + run_next_pa = pa + PAGE_SIZE; + run = 1; + } + } else if (pa == run_next_pa) { + run_next_pa += PAGE_SIZE; + run += 1; + } else { + run = 0; + } + + if (run == n) { + if (run_prev) + *((void **) run_prev) = next; + else + free = next; + return run_start; + } + } +} + + +void free_page(void *page) +{ + *(void **)page = free; + free = page; +} + diff --git a/lib/alloc_page.h b/lib/alloc_page.h new file mode 100644 index 0000000..1884c7a --- /dev/null +++ b/lib/alloc_page.h @@ -0,0 +1,16 @@ +/* + * This work is licensed under the terms of the GNU LGPL, version 2. + * + * This is a simple allocator that provides contiguous physical addresses + * with byte granularity. + */ + +#ifndef ALLOC_PAGE_H +#define ALLOC_PAGE_H 1 + +void *alloc_page(); +void *alloc_pages(unsigned long order); +void free_page(void *page); +void free_pages(void *mem, unsigned long size); + +#endif diff --git a/lib/x86/intel-iommu.c b/lib/x86/intel-iommu.c index 9fdbd3b..af92fab 100644 --- a/lib/x86/intel-iommu.c +++ b/lib/x86/intel-iommu.c @@ -12,8 +12,10 @@ #include "intel-iommu.h" #include "libcflat.h" +#include "vm.h" #include "pci.h" #include "atomic.h" +#include "alloc_page.h" /* * VT-d in QEMU currently only support 39 bits address width, which is diff --git a/lib/x86/intel-iommu.h b/lib/x86/intel-iommu.h index 885be53..05b9744 100644 --- a/lib/x86/intel-iommu.h +++ b/lib/x86/intel-iommu.h @@ -16,7 +16,6 @@ #define __INTEL_IOMMU_H__ #include "libcflat.h" -#include "vm.h" #include "isr.h" #include "smp.h" #include "desc.h" diff --git a/lib/x86/vm.c b/lib/x86/vm.c index b975a73..d2a3c59 100644 --- a/lib/x86/vm.c +++ b/lib/x86/vm.c @@ -2,111 +2,7 @@ #include "vm.h" #include "libcflat.h" #include "vmalloc.h" - -static void *free = 0; - -static void free_memory(void *mem, unsigned long size) -{ - void *end; - - assert_msg((unsigned long) mem % PAGE_SIZE == 0, - "mem not page aligned: %p", mem); - - assert_msg(size % PAGE_SIZE == 0, "size not page aligned: %#lx", size); - - assert_msg(size == 0 || mem + size > mem, - "mem + size overflow: %p + %#lx", mem, size); - - if (size == 0) { - free = NULL; - return; - } - - free = mem; - end = mem + size; - while (mem + PAGE_SIZE != end) { - *(void **)mem = (mem + PAGE_SIZE); - mem += PAGE_SIZE; - } - - *(void **)mem = NULL; -} - -void *alloc_page() -{ - void *p; - - if (!free) - return 0; - - p = free; - free = *(void **)free; - - return p; -} - -/* - * Allocates (1 << order) physically contiguous and naturally aligned pages. - * Returns NULL if there's no memory left. - */ -void *alloc_pages(unsigned long order) -{ - /* Generic list traversal. */ - void *prev; - void *curr = NULL; - void *next = free; - - /* Looking for a run of length (1 << order). */ - unsigned long run = 0; - const unsigned long n = 1ul << order; - const unsigned long align_mask = (n << PAGE_SHIFT) - 1; - void *run_start = NULL; - void *run_prev = NULL; - unsigned long run_next_pa = 0; - unsigned long pa; - - assert(order < sizeof(unsigned long) * 8); - - for (;;) { - prev = curr; - curr = next; - next = curr ? *((void **) curr) : NULL; - - if (!curr) - return 0; - - pa = virt_to_phys(curr); - - if (run == 0) { - if (!(pa & align_mask)) { - run_start = curr; - run_prev = prev; - run_next_pa = pa + PAGE_SIZE; - run = 1; - } - } else if (pa == run_next_pa) { - run_next_pa += PAGE_SIZE; - run += 1; - } else { - run = 0; - } - - if (run == n) { - if (run_prev) - *((void **) run_prev) = next; - else - free = next; - return run_start; - } - } -} - - -void free_page(void *page) -{ - *(void **)page = free; - free = page; -} +#include "alloc_page.h" extern char edata; static unsigned long end_of_memory; @@ -290,7 +186,7 @@ void setup_vm() { assert(!end_of_memory); end_of_memory = fwcfg_get_u64(FW_CFG_RAM_SIZE); - free_memory(&edata, end_of_memory - (unsigned long)&edata); + free_pages(&edata, end_of_memory - (unsigned long)&edata); setup_mmu(end_of_memory); } diff --git a/lib/x86/vm.h b/lib/x86/vm.h index 543da33..4a7888b 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -40,10 +40,6 @@ unsigned long *install_pte(unsigned long *cr3, unsigned long pte, unsigned long *pt_page); -void *alloc_page(); -void *alloc_pages(unsigned long order); -void free_page(void *page); - 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); diff --git a/x86/Makefile.common b/x86/Makefile.common index f3f3742..fce0801 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -5,6 +5,7 @@ all: directories test_cases cflatobjs += lib/pci.o cflatobjs += lib/pci-edu.o cflatobjs += lib/vmalloc.o +cflatobjs += lib/alloc_page.o cflatobjs += lib/x86/setup.o cflatobjs += lib/x86/io.o cflatobjs += lib/x86/smp.o diff --git a/x86/emulator.c b/x86/emulator.c index 4fb0f32..e6f27cc 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -5,6 +5,7 @@ #include "types.h" #include "processor.h" #include "vmalloc.h" +#include "alloc_page.h" #define memset __builtin_memset #define TESTDEV_IO_PORT 0xe0 diff --git a/x86/eventinj.c b/x86/eventinj.c index 61e1b96..247604c 100644 --- a/x86/eventinj.c +++ b/x86/eventinj.c @@ -1,11 +1,12 @@ #include "libcflat.h" -#include "processor.h" #include "vm.h" +#include "processor.h" #include "desc.h" #include "isr.h" #include "apic.h" #include "apic-defs.h" #include "vmalloc.h" +#include "alloc_page.h" #ifdef __x86_64__ # define R "r" diff --git a/x86/hypercall.c b/x86/hypercall.c index 9380f78..37fec8e 100644 --- a/x86/hypercall.c +++ b/x86/hypercall.c @@ -1,6 +1,7 @@ #include "libcflat.h" #include "vm.h" #include "desc.h" +#include "alloc_page.h" #define KVM_HYPERCALL_INTEL ".byte 0x0f,0x01,0xc1" #define KVM_HYPERCALL_AMD ".byte 0x0f,0x01,0xd9" diff --git a/x86/hyperv_clock.c b/x86/hyperv_clock.c index 9497269..b72e357 100644 --- a/x86/hyperv_clock.c +++ b/x86/hyperv_clock.c @@ -4,6 +4,7 @@ #include "processor.h" #include "hyperv.h" #include "vm.h" +#include "alloc_page.h" #define MAX_CPU 4 #define TICKS_PER_SEC (1000000000 / 100) diff --git a/x86/hyperv_connections.c b/x86/hyperv_connections.c index b061048..5d541c9 100644 --- a/x86/hyperv_connections.c +++ b/x86/hyperv_connections.c @@ -5,6 +5,7 @@ #include "atomic.h" #include "hyperv.h" #include "bitops.h" +#include "alloc_page.h" #define MAX_CPUS 64 diff --git a/x86/hyperv_stimer.c b/x86/hyperv_stimer.c index bd7f966..b6332fd 100644 --- a/x86/hyperv_stimer.c +++ b/x86/hyperv_stimer.c @@ -9,6 +9,7 @@ #include "atomic.h" #include "hyperv.h" #include "asm/barrier.h" +#include "alloc_page.h" #define MAX_CPUS 4 diff --git a/x86/hyperv_synic.c b/x86/hyperv_synic.c index 1ccf1a0..9a5f53f 100644 --- a/x86/hyperv_synic.c +++ b/x86/hyperv_synic.c @@ -8,6 +8,7 @@ #include "smp.h" #include "atomic.h" #include "hyperv.h" +#include "alloc_page.h" #define MAX_CPUS 4 diff --git a/x86/intel-iommu.c b/x86/intel-iommu.c index 610cc65..82b8234 100644 --- a/x86/intel-iommu.c +++ b/x86/intel-iommu.c @@ -13,6 +13,8 @@ #include "intel-iommu.h" #include "pci-edu.h" #include "x86/apic.h" +#include "vm.h" +#include "alloc_page.h" #define VTD_TEST_DMAR_4B ("DMAR 4B memcpy test") #define VTD_TEST_IR_MSI ("IR MSI") diff --git a/x86/rmap_chain.c b/x86/rmap_chain.c index 7bf6275..97591f9 100644 --- a/x86/rmap_chain.c +++ b/x86/rmap_chain.c @@ -4,6 +4,7 @@ #include "fwcfg.h" #include "vm.h" #include "smp.h" +#include "alloc_page.h" int main (void) { diff --git a/x86/svm.c b/x86/svm.c index 25ac0ce..162632c 100644 --- a/x86/svm.c +++ b/x86/svm.c @@ -6,6 +6,7 @@ #include "vm.h" #include "smp.h" #include "types.h" +#include "alloc_page.h" /* for the nested page table*/ u64 *pml4e; diff --git a/x86/taskswitch2.c b/x86/taskswitch2.c index bb7345b..22f0b6b 100644 --- a/x86/taskswitch2.c +++ b/x86/taskswitch2.c @@ -4,6 +4,7 @@ #include "apic.h" #include "processor.h" #include "vm.h" +#include "alloc_page.h" #define MAIN_TSS_SEL (FIRST_SPARE_SEL + 0) #define VM86_TSS_SEL (FIRST_SPARE_SEL + 8) diff --git a/x86/vmx.c b/x86/vmx.c index 786c70f..cc76b5b 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -30,6 +30,7 @@ #include "libcflat.h" #include "processor.h" +#include "alloc_page.h" #include "vm.h" #include "desc.h" #include "vmx.h" diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index d9bbe10..1c9c747 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -13,6 +13,7 @@ #include "apic.h" #include "types.h" #include "vmalloc.h" +#include "alloc_page.h" #define NONCANONICAL 0xaaaaaaaaaaaaaaaaull -- 2.14.2