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时建立映射.