Chinaunix首页 | 论坛 | 博客
  • 博客访问: 38451
  • 博文数量: 23
  • 博客积分: 1065
  • 博客等级: 少尉
  • 技术积分: 185
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-14 15:32
文章分类

全部博文(23)

文章存档

2010年(20)

2008年(3)

我的朋友
最近访客

分类: LINUX

2010-03-01 23:56:42

¤、内核页目录的初始化

/* 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
}
阅读(548) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~