内核页目录的初始化
/* swapper_pg_dir is the main page directory, address 0x00101000*/
>>> 内核页目录,第0,1项和第768、767项均为映射到物理内存0-8M的页目录项
>>> 其页表的物理地址是0x00102000和0x00103000,即下面的pg0和pg1所在的位置
>>> (在启动的时候,将内核映像移到0x0010000处)。
>>> 之所以第0,1项与第768和767相同,是因为在开启分页前的线性地址0-8M和开启
>>> 分页之后的3G-3G+8M均映射到相同的物理地址0-8M
/*
* This is initialized to create an identity-mapping at 0-8M (for bootup
* purposes) and another mapping of the 0-8M area at virtual address
* PAGE_OFFSET.
*/
.org 0x1000
ENTRY(swapper_pg_dir)
.long 0x00102007
.long 0x00103007
.fill BOOT_USER_PGD_PTRS-2,4,0
/* default: 766 entries */
.long 0x00102007
.long 0x00103007
/* default: 254 entries */
.fill BOOT_KERNEL_PGD_PTRS-2,4,0
/*
* The page tables are initialized to only 8MB here - the final page
* tables are set up later depending on memory size.
*/
>>> 下面为物理地址0-8M的页表项
>>> 从0x4000到0x2000共2k个页表项,映射0-8M的物理内存
.org 0x2000
ENTRY(pg0)
.org 0x3000
ENTRY(pg1)
/*
* empty_zero_page must immediately follow the page tables ! (The
* initialization loop counts until empty_zero_page)
*/
.org 0x4000
ENTRY(empty_zero_page)
>>> 进程0的页目录指向swapper_pg_dir
#define INIT_MM(name) \
{ \
mmap: &init_mmap, \
mmap_avl: NULL, \
mmap_cache: NULL, \
pgd: swapper_pg_dir, \
mm_users: ATOMIC_INIT(2), \
mm_count: ATOMIC_INIT(1), \
map_count: 1, \
mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \
page_table_lock: SPIN_LOCK_UNLOCKED, \
mmlist: LIST_HEAD_INIT(name.mmlist), \
}
/*
* paging_init() sets up the page tables - note that the first 8MB are
* already mapped by head.S.
*
* This routines also unmaps the page at virtual kernel address 0, so
* that we can trap those pesky NULL-reference errors in the kernel.
*/
void __init paging_init(void)
{
pagetable_init();
__asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
。。。。。。。。。。。
}
static void __init pagetable_init (void)
{
unsigned long vaddr, end;
pgd_t *pgd, *pgd_base;
int i, j, k;
pmd_t *pmd;
pte_t *pte, *pte_base;
>>> end虚拟空间的最大值(最大物理内存+3G)
/*
* This can be zero as well - no problem, in that case we exit
* the loops anyway due to the PTRS_PER_* conditions.
*/
end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
pgd_base = swapper_pg_dir;
#if CONFIG_X86_PAE
for (i = 0; i < PTRS_PER_PGD; i++)
set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page)));
#endif
>>> 内核起始虚拟空间在内核页目录表中的索引
i = __pgd_offset(PAGE_OFFSET);
pgd = pgd_base + i;
>>> #define PTRS_PER_PGD 1024
>>> 对页目录的从768项开始的每一项
for (; i < PTRS_PER_PGD; pgd++, i++) {
>>> vaddr为第i项页目录项所映射的内核空间的起始虚拟地址,PGDIR_SIZE=4M
vaddr = i*PGDIR_SIZE;
if (end && (vaddr >= end))
break;
#if CONFIG_X86_PAE
pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
set_pgd(pgd, __pgd(__pa(pmd) + 0x1));
#else
>>> 对两级映射机制,pmd实际上是pgd
pmd = (pmd_t *)pgd;
#endif
if (pmd != pmd_offset(pgd, 0))
BUG();
for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
if (end && (vaddr >= end))
break;
>>> 假如内核不支持 Page Size Extensions
if (cpu_has_pse) {
。。。。。。。。。。
}
>>> 分配内核页表
pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
>>> 对每一项页表项
for (k = 0; k < PTRS_PER_PTE; pte++, k++) {
vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
if (end && (vaddr >= end))
break;
>>> 将页面的物理地址填入页表项中
*pte = mk_pte_phys(__pa(vaddr), PAGE_KERNEL);
}
>>> 将页表的物理地址填入到页目录项中
set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
if (pte_base != pte_offset(pmd, 0))
BUG();
}
}
/*
* 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;
fixrange_init(vaddr, 0, pgd_base);
#if CONFIG_HIGHMEM
。。。。。。。。。。。。
#endif
#if CONFIG_X86_PAE
。。。。。。。。。。。。
#endif
}
阅读(1157) | 评论(0) | 转发(0) |