paging

it2026-02-12  16

paging_init()    setup.S->start_kernel(void) -> setup_arch -> paging_init() (1)    接下来是paging_init,调用下面的pagetable_init,初始化页表然后重新加 载cr3,flush tlb,然后使用kmap_init为kmap_automic使用的变量求值,..... 不算复杂,重要的是free_area_init,初始化了zone-buddy内存管理系统(设置 所有页面都是PG_reserved(free_all_bootmem,负责重置)). void __init paging_init(void) { #ifdef CONFIG_X86_PAE          set_nx();          if (nx_enabled)                  printk("NX (Execute Disable) protection: active\n");  #endif            pagetable_init();            load_cr3(swapper_pg_dir);    #ifdef CONFIG_X86_PAE          /*           * We will bail out later - printk doesn't work right now so           * the user would just see a hanging kernel.           */          if (cpu_has_pae)                  set_in_cr4(X86_CR4_PAE);  #endif          __flush_tlb_all();      //load 了cr3...            kmap_init();  } (2)/mm/init.c swapper_pg_dir 静态分配的 pgd_t swapper_pg_dir[1024]; //删了config_pae的代码 内核在使用虚拟空间: +------------------------------------------------------------------      |   8K空洞 +------------------------------------------------------------------ |   FIXADDR_TOP(0xffffe000UL)            (include/asm-i386/fixmap.h) |   fixed map(每项4k虚存,见FIXADDR_SIZE)       |      { //fix map 内容 (enum fixed_addresses) |         FIX_APIC_BASE,  |     FIX_IO_APIC_BASE_0, |   FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1 |  |   FIX_CO_CPU, /* Cobalt timer */ |   FIX_CO_APIC, /* Cobalt APIC Redirection Table */  |   FIX_LI_PCIA, /* Lithium PCI Bridge A */ |   FIX_LI_PCIB, /* Lithium PCI Bridge B */ +-------------- #ifdef CONFIG_HIGHMEM   /*为fix KMAP预留每cpu 8k的虚存,读写各4k*/ |    FIX_KMAP_BEGIN,  /* 主要用于kmap_atomic*/ |    FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif +-------------- |    __end_of_fixed_addresses |       } |   FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) +-------------------------------------------------------------------- |   VMALLOC_END (FIXADDR_START)  (include/asm-i386/pgtable.h) |       +------------------ |       |  xxxxx: kmap 和 vmalloc 相互重叠,2.6已经修正 |       |     kmap 使用的4M虚存  (asm/highmem.h,LAST_PKMAP) |       |  PKMAP_BASE (0xfe000000UL) (距离4G 32M) |       +------------------ |     vmalloc 映射区 |   VMALLOC_START (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) |                  & \~(VMALLOC_OFFSET-1)) /*down align 8M */ +-------------------------------------------------------------------- |   约 8M 空洞 +-------------------------------------------------------------------- |   high_memory (见003___arch_i386_mm_ioremap.c 对此的分析)  ..一定映射到内核虚拟空间???,不可以是fixaddr么??? |      内核已经映射了的物理页面 MAX 896M | | |   3G +-------------------------------------------------------------------- |   resoved for app 0-3G +-------------------------------------------------------------------- (3) pagetable_init  static void __init pagetable_init (void)  {          unsigned long vaddr;          pgd_t *pgd_base = swapper_pg_dir;          /* Enable PSE if available */          if (cpu_has_pse) {                  set_in_cr4(X86_CR4_PSE);          }            /* Enable PGE if available */          if (cpu_has_pge) {                  set_in_cr4(X86_CR4_PGE);                  __PAGE_KERNEL |= _PAGE_GLOBAL;                  __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;          }            kernel_physical_mapping_init(pgd_base);          remap_numa_kva();            /*           * Fixed mappings, only the page table structure has to be           * created - mappings will be set by set_fixmap():           */          vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;          page_table_range_init(vaddr, 0, pgd_base);    //这里用0,应该是超过了4G,或者2^64,回饶,所以是0             permanent_kmaps_init(pgd_base);  }   /* This maps the physical memory to kernel virtual address space, a total    * of max_low_pfn pages, by creating page tables starting from address    * PAGE_OFFSET.   */  PAGE_OFFSET      0xc0000000 //初始化页目录,页表,, //1页目录 = 1 * (4k/4) * 4k = 4M,    896M,所以要用掉页目录表中的 896/4 = 225项   //pse设置话是一页面是4MB了, //这样 (4) kernel_physical_mapping_init  static void __init kernel_physical_mapping_init(pgd_t *pgd_base)  {          unsigned long pfn;          pgd_t *pgd;          pmd_t *pmd;          pte_t *pte;          int pgd_idx, pmd_idx, pte_ofs;            pgd_idx = pgd_index(PAGE_OFFSET);   //内核虚拟地址开始处....          pgd = pgd_base + pgd_idx;          pfn = 0;            for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {                  pmd = one_md_table_init(pgd);  //This only returns the pgd entry ,即pmd = pgd..                  if (pfn >= max_low_pfn)                          continue;                  for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {                          unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;                            /* Map with big pages if possible, otherwise create normal page tables. */                          if (cpu_has_pse) {                                                } else {                                  pte = one_page_table_init(pmd);  //获得页表指针,没有则分配页表.设置pgd,(二级,pmd就是pgd)                                    for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {                                                  if (is_kernel_text(address))   //是不是内核text                                                          set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));                                                  else                                                          set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));                                  }                          }                  }          }  }     /*    * Create a page table and place a pointer to it in a middle page    * directory entry.    */   static pte_t * __init one_page_table_init(pmd_t *pmd)   {           if (pmd_none(*pmd)) {      //开始时,pmd为none,分配pte_t表...然后建立映射.                   pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);                   set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));     //设置页面目录.                   if (page_table != pte_offset_kernel(pmd, 0))                           BUG();                        return page_table;           }                      return pte_offset_kernel(pmd, 0);   }     #define pte_offset_kernel(dir, address) \          ((pte_t *) pmd_page_kernel(*(dir)) +  pte_index(address))  #define pmd_page_kernel(pmd) \                  ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))   (5) page_table_range_init  ,,,没设置pte...因为这是用来映射高端内存的或者别的用途?.要用的时候再设置pte项..而不是永久映射.  static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)  {          pgd_t *pgd;          pud_t *pud;          pmd_t *pmd;          int pgd_idx, pmd_idx;          unsigned long vaddr;            vaddr = start;          pgd_idx = pgd_index(vaddr);          pmd_idx = pmd_index(vaddr);          pgd = pgd_base + pgd_idx;            for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {                  if (pgd_none(*pgd))               //永远为0..因为pmd总是存在   /*    * The "pgd_xxx()" functions here are trivial for a folded two-level    * setup: the pud is never bad, and a pud always exists (as it's folded    * into the pgd entry)    */   static inline int pgd_none(pgd_t pgd)           { return 0; }                          one_md_table_init(pgd);                      pud = pud_offset(pgd, vaddr);                  pmd = pmd_offset(pud, vaddr);                  for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {                          if (pmd_none(*pmd))               //实际上就是页表为空?                                  one_page_table_init(pmd); //设置页目录项                            vaddr += PMD_SIZE;                  }                  pmd_idx = 0;          }  } (6)  permanent_kmaps_init  没设置pte...因为这是用来映射高端内存的.要用的时候再设置pte项 /* *为fix KMAP预留每cpu 8k的虚存,读写各4k*/   /*    * Ordering is:    *    * FIXADDR_TOP    *                      fixed_addresses    * FIXADDR_START    *                      temp fixed addresses    * FIXADDR_BOOT_START    *                      Persistent kmap area    * PKMAP_BASE    * VMALLOC_END    *                      Vmalloc area    * VMALLOC_START    * high_memory    */   #define PKMAP_BASE ( (FIXADDR_BOOT_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK )  static void __init permanent_kmaps_init(pgd_t *pgd_base)  {          pgd_t *pgd;          pud_t *pud;          pmd_t *pmd;          pte_t *pte;          unsigned long vaddr;            vaddr = PKMAP_BASE;          page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);  //还是调用上一个函数.设置好,页目录项            pgd = swapper_pg_dir + pgd_index(vaddr);          pud = pud_offset(pgd, vaddr);          pmd = pmd_offset(pud, vaddr);          pte = pte_offset_kernel(pmd, vaddr); //返回页表指针.           pkmap_page_table = pte;   }   #ifdef CONFIG_X86_PAE   #define LAST_PKMAP 512   #else   #define LAST_PKMAP 1024   #endif 所以kmap可以分配1024*4k= 4M空间. (7)  atomic 的高端内存...  static void __init kmap_init(void)  {          unsigned long kmap_vstart;            /* cache the first kmap pte */          kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);          kmap_pte = kmap_get_fixmap_pte(kmap_vstart);            kmap_prot = PAGE_KERNEL;  } (8)vmalloc的区间没有建立映射.. 应该vmalloc时建立映射.

转载于:https://www.cnblogs.com/fengguangqin/archive/2009/04/27/1444463.html

最新回复(0)