[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [PATCH v3 28/43] arm64: init the memory system
On Thu, Apr 26, 2018 at 02:10:01PM +0100, Julien Grall wrote: > Hi, > > On 16/04/18 07:32, Huang Shijie wrote: > >This patch do followings to initialize the memory system: > > 0.) Map extra 2M for the first_free_pfn. > > What guarantees you there will be free space after the kernel? And why only > 2MB? I add a limit to mini-os (arm64), if the memory is less then 4M, the mini-os will not run. 2MB is enough to provide pages for setting up the page table. > > As I have already said before, most likely you want to include a couple of > more page-table in the image directly. I tried, but I donot know how many pages should be preserved in the image directly. > > > > > 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 | 238 > > +++++++++++++++++++++++++++++++++++++++++++++++++ > > arch/arm/setup.c | 3 + > > include/arm/arch_mm.h | 5 ++ > > 4 files changed, 249 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..ed59159 100644 > >--- a/arch/arm/mm.c > >+++ b/arch/arm/mm.c > >@@ -6,6 +6,7 @@ > > #include <mini-os/posix/limits.h> > > #include <libfdt.h> > > #include <lib.h> > >+#include <arm64/pagetable.h> > > paddr_t physical_address_offset; > > unsigned mem_blocks = 1; > >@@ -23,6 +24,236 @@ unsigned long allocate_ondemand(unsigned long n, > >unsigned long alignment) > > BUG(); > > } > >+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, > > You are using the term pte, pmd, pud (which basically looks very > Linuxism...) but I have not idea what you are refer to in Mini-OS context. > Please explain it. sorry, what is the "Mini-OS context" stand for? > > >+ paddr_t phys, uint64_t mem_type, > >+ paddr_t (*new_page)(void), int level) > > The indentation looks wrong. okay > > >+{ > >+ 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) > > indentation. okay.. > > > >+{ > >+ 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) > > Indentation. > > Also, this is a bit weird to impose the caller to know the level where it > stops. How do you ensure the virtual and physical address are going to be > aligned properly? The one who uses build_pagetable() should pay attention to the alignment. Of court, we can add some alignment checks in the code too. > > >+{ > >+ 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; > > Please explain the purpose of the variable in a comment. okay. > > >+/* > >+ * 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(). > > Your API looks wrong, a caller of the PT mapping should not need to know the The build_pagetable() is only used internally, it is not a API function. > level it is going to map. The only thing necessary is the size of the > mapping. Please see the init_pagetable()/map_frames_virt()/ioremap, they are API function. > > >+ */ > >+ if (size >= L1_SIZE) { > >+ pgd = &boot_l0_pgtable[l0_pgt_idx(vaddr)]; > >+ if ((*pgd) == L0_INVAL) { > > I don't understand this code. Why do you need to check the boot table in > order to now the level to map? The (*pgd) maybe empty, so we need to check it. > > >+ 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; > >+} > >+ > > void arch_init_mm(unsigned long *start_pfn_p, unsigned long *max_pfn_p) > > { > > int memory; > >@@ -65,6 +296,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 +309,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 f77a210..db6e781 100644 > >--- a/include/arm/arch_mm.h > >+++ b/include/arm/arch_mm.h > >@@ -3,6 +3,10 @@ > > typedef uint64_t paddr_t; > > #define PRIpaddr "lx" > >+#define MIN_MEM_SIZE (0x400000) > > Where does this value come from? I added for the memory limit. If the memory size is less then 4M, the mini-os will not run. > > >+#define MAX_MEM_SIZE (1UL << 39) > > Same here? Refer to the x86. Of coure, We can change it. Thanks Huang Shijie _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |