[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [PATCH v2 29/47] arm64: init the memory system
This patch do followings to initialize the memory system: 0.) Map extra 2M for the first_free_pfn. 1.) add arch_mm_preinit() to setup the page table for Device Tree. 2.) add functions to setup the page table, such as early_alloc_page()/build_pagetable()/build_pud/build_pmd. 3.) Just as the x86 does, limits the max memory size to MAX_MEM_SIZE, the min memory size to MIN_MEM_SIZE, 4.) and setup the page allocator in arch_init_mm(). The init_pagetable() will find the best block mapping level to setup the page table. Signed-off-by: Huang Shijie <shijie.huang@xxxxxxx> --- arch/arm/arm64/arm64.S | 3 + arch/arm/mm.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++++ arch/arm/setup.c | 3 + include/arm/arch_mm.h | 7 ++ 4 files changed, 266 insertions(+) diff --git a/arch/arm/arm64/arm64.S b/arch/arm/arm64/arm64.S index 93ffc89..4e9c042 100644 --- a/arch/arm/arm64/arm64.S +++ b/arch/arm/arm64/arm64.S @@ -232,6 +232,9 @@ _setup_initial_pgtable: ldr x0, =_text /* x0 := vaddr(_text) */ ldr x1, =_end /* x1 := vaddr(_end) */ + /* Map extra 2M for first_free_pfn */ + add x1, x1, L2_SIZE + set_page_table x0, 0, PT_PT set_page_table x0, 1, PT_PT 1: diff --git a/arch/arm/mm.c b/arch/arm/mm.c index d98fad8..23a23e1 100644 --- a/arch/arm/mm.c +++ b/arch/arm/mm.c @@ -23,6 +23,252 @@ unsigned long allocate_ondemand(unsigned long n, unsigned long alignment) BUG(); } +#if defined(__aarch64__) + +#include <arm64/pagetable.h> + +extern lpae_t boot_l0_pgtable[512]; + +static inline void set_pgt_entry(lpae_t *ptr, lpae_t val) +{ + *ptr = val; + dsb(ishst); + isb(); +} + +static void build_pte(lpae_t *pmd, unsigned long vaddr, unsigned long vend, + paddr_t phys, uint64_t mem_type) +{ + lpae_t *pte; + + pte = (lpae_t *)to_virt((*pmd) & ~ATTR_MASK_L) + l3_pgt_idx(vaddr); + do { + set_pgt_entry(pte, (phys & L3_MASK) | mem_type | L3_PAGE); + + vaddr += L3_SIZE; + phys += L3_SIZE; + pte++; + } while (vaddr < vend); +} + +static int build_pmd(lpae_t *pud, unsigned long vaddr, unsigned long vend, + paddr_t phys, uint64_t mem_type, + paddr_t (*new_page)(void), int level) +{ + lpae_t *pmd; + unsigned long next; + + pmd = (lpae_t *)to_virt((*pud) & ~ATTR_MASK_L) + l2_pgt_idx(vaddr); + do { + if (level == 2) { + set_pgt_entry(pmd, (phys & L2_MASK) | mem_type | L2_BLOCK); + } else { + next = vaddr + L2_SIZE; + if (next > vend) + next = vend; + + if ((*pmd) == L2_INVAL) { + paddr_t newpage = new_page(); + if (!newpage) + return -ENOMEM; + set_pgt_entry(pmd, newpage | PT_PT); + } + + build_pte(pmd, vaddr, next, phys, mem_type); + } + + vaddr += L2_SIZE; + phys += L2_SIZE; + pmd++; + } while (vaddr < vend); + + return 0; +} + +static int build_pud(lpae_t *pgd, unsigned long vaddr, unsigned long vend, + paddr_t phys, uint64_t mem_type, + paddr_t (*new_page)(void), int level) +{ + lpae_t *pud; + unsigned long next; + int ret; + + pud = (lpae_t *)to_virt((*pgd) & ~ATTR_MASK_L) + l1_pgt_idx(vaddr); + do { + if (level == 1) { + set_pgt_entry(pud, (phys & L1_MASK) | mem_type | L1_BLOCK); + } else { + next = vaddr + L1_SIZE; + if (next > vend) + next = vend; + + if ((*pud) == L1_INVAL) { + paddr_t newpage = new_page(); + if (!newpage) + return -ENOMEM; + set_pgt_entry(pud, newpage | PT_PT); + } + + ret = build_pmd(pud, vaddr, next, phys, mem_type, new_page, level); + if (ret) + return ret; + } + + vaddr += L1_SIZE; + phys += L1_SIZE; + pud++; + } while (vaddr < vend); + + return 0; +} + +static int build_pagetable(unsigned long vaddr, unsigned long start_pfn, + unsigned long max_pfn, uint64_t mem_type, + paddr_t (*new_page)(void), int level) +{ + paddr_t p_start; + unsigned long v_end, next; + lpae_t *pgd; + int ret; + + v_end = vaddr + max_pfn * PAGE_SIZE; + p_start = PFN_PHYS(start_pfn); + + pgd = &boot_l0_pgtable[l0_pgt_idx(vaddr)]; + + do { + next = (vaddr + L0_SIZE); + if (next > v_end) + next = v_end; + + if ((*pgd) == L0_INVAL) { + paddr_t newpage = new_page(); + if (!newpage) + return -ENOMEM; + set_pgt_entry(pgd, newpage | PT_PT); + } + + ret = build_pud(pgd, vaddr, next, p_start, mem_type, new_page, level); + if (ret) + return ret; + + p_start += next - vaddr; + vaddr = next; + pgd++; + } while (vaddr != v_end); + + return 0; +} + +/* + * Before the page allocator is ready, we use first_free_pfn to record + * the first free page. The first_free_pfn will be increased by + * early_alloc_page(). + */ +static unsigned long first_free_pfn; + +/* The pfn for MIN_MEM_SIZE */ +static unsigned long min_mem_pfn; + +static paddr_t early_alloc_page(void) +{ + paddr_t new_page; + + memset(pfn_to_virt(first_free_pfn), 0, PAGE_SIZE); + dsb(ishst); + + new_page = PFN_PHYS(first_free_pfn); + first_free_pfn++; + ASSERT(first_free_pfn < min_mem_pfn); + return new_page; +} + +static int init_pagetable_ok; +/* + * This function will setup the page table for the memory system. + */ +void init_pagetable(unsigned long *start_pfn, unsigned long base, + unsigned long size) +{ + unsigned long vaddr = (unsigned long)to_virt(base); + paddr_t phys = base; + paddr_t sz = L1_SIZE; + lpae_t *pgd; + lpae_t *pud; + int level; + + do { + /* + * We cannot set block mapping for PGD(level 0), + * but we can set block mapping for PUD(level 1) and PMD(level 2). + * Get the proper level for build_pagetable(). + */ + if (size >= L1_SIZE) { + pgd = &boot_l0_pgtable[l0_pgt_idx(vaddr)]; + if ((*pgd) == L0_INVAL) { + level = 1; + } else { + pud = (lpae_t *)to_virt((*pgd) & ~ATTR_MASK_L) + l1_pgt_idx(vaddr); + if ((*pud) == L1_INVAL) + level = 1; + else + level = 2; + } + } else { + sz = size & L2_MASK; + level = 2; + } + + build_pagetable(vaddr, PHYS_PFN(phys), PFN_UP(sz), + MEM_DEF_ATTR, early_alloc_page, level); + + vaddr += sz; + phys += sz; + size -= sz; + } while (size > L2_SIZE); + + /* Use the page mapping (level 3) for the left */ + if (size) + build_pagetable(vaddr, PHYS_PFN(phys), PFN_UP(size), + MEM_DEF_ATTR, early_alloc_page, 3); + + *start_pfn = first_free_pfn; + init_pagetable_ok = 1; +} + +void arch_mm_preinit(void *dtb_pointer) +{ + paddr_t **dtb_p = dtb_pointer; + paddr_t *dtb = *dtb_p; + uintptr_t end = (uintptr_t) &_end; + + dtb = to_virt(((paddr_t)dtb)); + first_free_pfn = PFN_UP(to_phys(end)); + min_mem_pfn = PFN_UP(to_phys(_text) + MIN_MEM_SIZE); + + /* + * Setup the mapping for Device Tree, only map 2M(L2_SIZE) size. + * + * Note: The early_alloc_page() will increase @first_free_pfn. + */ + build_pagetable((unsigned long)dtb, virt_to_pfn((unsigned long)dtb), + PHYS_PFN(L2_SIZE), MEM_DEF_ATTR, early_alloc_page, 2); + + *dtb_p = dtb; +} + +#else +void arch_mm_preinit(void *dtb_pointer) +{ +} + +void init_pagetable(unsigned long *start_pfn, unsigned long base, + unsigned long size) +{ +} + +#endif + void arch_init_mm(unsigned long *start_pfn_p, unsigned long *max_pfn_p) { int memory; @@ -65,6 +311,11 @@ void arch_init_mm(unsigned long *start_pfn_p, unsigned long *max_pfn_p) end = (uintptr_t) &_end; mem_base = fdt64_to_cpu(regs[0]); mem_size = fdt64_to_cpu(regs[1]); + + BUG_ON(mem_size < MIN_MEM_SIZE); + if (mem_size > MAX_MEM_SIZE) + mem_size = MAX_MEM_SIZE; + printk("Found memory at 0x%llx (len 0x%llx)\n", (unsigned long long) mem_base, (unsigned long long) mem_size); @@ -73,6 +324,8 @@ void arch_init_mm(unsigned long *start_pfn_p, unsigned long *max_pfn_p) heap_len = mem_size - (PFN_PHYS(*start_pfn_p) - mem_base); *max_pfn_p = *start_pfn_p + PFN_DOWN(heap_len); + init_pagetable(start_pfn_p, mem_base, mem_size); + printk("Using pages %lu to %lu as free space for heap.\n", *start_pfn_p, *max_pfn_p); /* The device tree is probably in memory that we're about to hand over to the page diff --git a/arch/arm/setup.c b/arch/arm/setup.c index 27bea4a..ab82eda 100644 --- a/arch/arm/setup.c +++ b/arch/arm/setup.c @@ -29,6 +29,9 @@ void arch_init(void *dtb_pointer, paddr_t physical_offset) xprintk("Virtual -> physical offset = %"PRIpaddr" \n", physical_address_offset); + /* Do the preparations */ + arch_mm_preinit(&dtb_pointer); + xprintk("Checking DTB at %p...\n", dtb_pointer); if ((r = fdt_check_header(dtb_pointer))) { diff --git a/include/arm/arch_mm.h b/include/arm/arch_mm.h index 231247c..7bfb942 100644 --- a/include/arm/arch_mm.h +++ b/include/arm/arch_mm.h @@ -4,11 +4,17 @@ #if defined(__arm__) typedef uint32_t paddr_t; #define PRIpaddr "x" +#define MIN_MEM_SIZE (0x400000) +#define MAX_MEM_SIZE (~0UL) #else typedef uint64_t paddr_t; #define PRIpaddr "lx" +#define MIN_MEM_SIZE (0x400000) +#define MAX_MEM_SIZE (1UL << 39) #endif +typedef uint64_t lpae_t; + extern char _text, _etext, _erodata, _edata, _end, __bss_start; extern int _boot_stack[]; extern int _boot_stack_end[]; @@ -35,6 +41,7 @@ extern paddr_t physical_address_offset; #define virtual_to_mfn(_virt) virt_to_mfn(_virt) +void arch_mm_preinit(void *dtb_pointer); // FIXME #define map_frames(f, n) (NULL) -- 2.7.4 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |