前面已经分析过了Intel的内存映射和linux的基本使用情况,已知head_32.S仅是建立临时页表,内核还是要建立内核页表,做到全面映射的。下面就基于RAM大于896MB,而小于4GB ,切CONFIG_HIGHMEM配置了高端内存的环境情况进行分析。

    建立内核页表前奏,了解两个很关键的变量:

max_pfn:最大物理内存页面帧号;

max_low_pfn:低端内存区(直接映射空间区的内存)的最大可用页帧号;
&nbsp; &nbsp;&nbsp;max_pfn 的值来自<span style="-ms-word-wrap: break-word;">setup_arch()</span>中,<span style="-ms-word-wrap: break-word;">setup_arch()</span>函数中有:

max_pfn = e820_end_of_ram_pfn();

&nbsp; &nbsp;&nbsp;那么接下来看一下<span style="-ms-word-wrap: break-word;">e820_end_of_ram_pfn()</span>的实现:


1. 【file:/arch/x86/kernel/e820.c】
2. unsigned long __init e820_end_of_ram_pfn(void)
3. {
4.     return e820_end_pfn(MAX_ARCH_PFN, E820_RAM);
5. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; e820_end_of_ram_pfn()直接封装调用</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">e820_end_pfn()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,而其入参为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MAX_ARCH_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">和</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">E820_RAM</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,其中</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MAX_ARCH_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">的定义(</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">x86</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">的</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">32bit</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">环境)为:</span>

#  define MAX_ARCH_PFN              (1ULL<<(32-PAGE_SHIFT))

&nbsp; &nbsp;&nbsp;最终值为<span style="-ms-word-wrap: break-word;">0x100000</span>,它表示的是<span style="-ms-word-wrap: break-word;">4G</span>物理内存的最大页面帧号;而<span style="-ms-word-wrap: break-word;">E820_RAM</span>为:

#define E820_RAM                 1

&nbsp; &nbsp;&nbsp;接下来看一下<span style="-ms-word-wrap: break-word;">e820_end_pfn()</span>函数实现:


1. 【file:/arch/x86/kernel/e820.c】
2. /
3.   Find the highest page frame number we have available
4.  /
5. static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type)
6. {
7.     int i;
8.     unsigned long last_pfn = 0;
9.     unsigned long max_arch_pfn = MAX_ARCH_PFN;
10.  
11.     for (i = 0; i < e820.nr_map; i++) {
12.         struct e820entry ei = &e820.map[i];
13.         unsigned long start_pfn;
14.         unsigned long end_pfn;
15.  
16.         if (ei->type != type)
17.             continue;
18.  
19.         start_pfn = ei->addr >> PAGE_SHIFT;
20.         end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT;
21.  
22.         if (start_pfn >= limit_pfn)
23.             continue;
24.         if (end_pfn > limit_pfn) {
25.             last_pfn = limit_pfn;
26.             break;
27.         }
28.         if (end_pfn > last_pfn)
29.             last_pfn = end_pfn;
30.     }
31.  
32.     if (last_pfn > max_arch_pfn)
33.         last_pfn = max_arch_pfn;
34.  
35.     printk(KERN_INFO "e820: last_pfn = %#lx max_arch_pfn = %#lx\n",
36.              last_pfn, max_arch_pfn);
37.     return last_pfn;
38. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 这个函数用来查找最大物理的页面帧号,通过对</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">e820</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">图的内存块信息得到内存块的起始地址,将起始地址右移</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">PAGE_SHIFT</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,算出其起始地址对应的页面帧号,如果足够大,超出了</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">limit_pfn</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">则设置最大页面帧号为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">limit_pfn</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,否则则设置为遍历中找到的最大的</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">last_pfn</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">。</span>

&nbsp; &nbsp; &nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">e820_end_of_ram_pfn()函数的调用位置:</span>

start_kernel()                           #/init/main.c

└─<span style="-ms-word-wrap: break-word;">&gt;setup_arch()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #/arch/x86/kernel/setup.c</span>


├─<span style="-ms-word-wrap: break-word;">&gt;e820_end_of_ram_pfn()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#/arch/x86/kernel/e820.c</span>


└─<span style="-ms-word-wrap: break-word;">&gt;find_low_pfn_range()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #/arch/x86/kernel/e820.c</span>
&nbsp; &nbsp;&nbsp;其中<span style="-ms-word-wrap: break-word;">find_low_pfn_range()</span>用于查找低端内存的最大页面数的 ,<span style="-ms-word-wrap: break-word;">max_low_pfn</span>则在这里面初始化。

&nbsp; &nbsp;&nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">find_low_pfn_range()代码实现:</span>


1. 【file:/arch/x86/mm/init_32.c】
2. /
3.   Determine low and high memory ranges:
4.  /
5. void __init find_low_pfn_range(void)
6. {
7.     / it could update max_pfn */
8.  
9.     if (max_pfn <= MAXMEM_PFN)
10.         lowmem_pfn_init();
11.     else
12.         highmem_pfn_init();
13. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 函数实现很简单,根据</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">max_pfn</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">是否大于</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MAXMEM_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,从而判断是否初始化高端内存,也可以认为是启用。那么来看一下</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MAXMEM_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">的宏定义:</span>

(file:/arch/x86/include/asm/setup.h)

#define MAXMEM_PFN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PFN_DOWN(MAXMEM)
&nbsp; &nbsp;&nbsp;其中<span style="-ms-word-wrap: break-word;">PFN_DOWN(x)</span>的定义为:

(file:/include/linux/pfn.h)

#define PFN_DOWN(x)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((x) &gt;&gt; PAGE_SHIFT)
&nbsp; &nbsp;&nbsp;PFN_DOWN(x)是用来返回小于<span style="-ms-word-wrap: break-word;">x</span>的最后一个页面号,对应的还有个<span style="-ms-word-wrap: break-word;">PFN_UP(x)</span>是用来返回大于<span style="-ms-word-wrap: break-word;">x</span>的第一个页面号,此外还有个<span style="-ms-word-wrap: break-word;">PFN_PHYS(x)</span>返回的是<span style="-ms-word-wrap: break-word;">x</span>的物理页面号。接着看<span style="-ms-word-wrap: break-word;">MAXMEM</span>的定义:

(file:arch/x86/include/asm/pgtable_32_types.h)

#define MAXMEM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE)
&nbsp; &nbsp;&nbsp;那么<span style="-ms-word-wrap: break-word;">VMALLOC_END</span>的定义则为:

(file:arch/x86/include/asm/pgtable_32_types.h)

#define VMALLOC_END&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (PKMAP_BASE - 2 * PAGE_SIZE)


#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) &amp; PMD_MASK)
&nbsp; &nbsp;&nbsp;其中<span style="-ms-word-wrap: break-word;">PKMAP_BASE</span>是永久映射空间的起始地址,<span style="-ms-word-wrap: break-word;">LAST_PKMAP</span>则是永久映射空间的映射页面数,定义为:

#define LAST_PKMAP 1024

&nbsp; &nbsp;&nbsp;另外<span style="-ms-word-wrap: break-word;">PAGE_SHIFT</span>和<span style="-ms-word-wrap: break-word;">PAGE_SIZE</span>的定义为:

#define PAGE_SHIFT               12

#define PAGE_SIZE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (_AC(1,UL) &lt;&lt; PAGE_SHIFT)
&nbsp; &nbsp;&nbsp;而<span style="-ms-word-wrap: break-word;">FIXADDR_BOOT_START</span>是临时固定映射空间起始地址,其的相关宏定义:

#define FIXADDR_BOOT_SIZE        (__end_of_fixed_addresses << PAGE_SHIFT)

#define FIXADDR_BOOT_START&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (FIXADDR_TOP - FIXADDR_BOOT_SIZE)


unsigned long __FIXADDR_TOP = 0xfffff000;


extern unsigned long __FIXADDR_TOP;


#define FIXADDR_TOP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ((unsigned long)__FIXADDR_TOP)
&nbsp; &nbsp;&nbsp;这里其中的<span style="-ms-word-wrap: break-word;">__end_of_fixed_addresses</span>是来自<span style="-ms-word-wrap: break-word;">fixed_addresses</span>枚举值,是固定映射的一个标志。此外这里的<span style="-ms-word-wrap: break-word;">FIXADDR_TOP</span>是固定映射区末尾,而另外还有一个这里未列出的<span style="-ms-word-wrap: break-word;">FIXADDR_START</span>,是固定映射区起始地址。

&nbsp; &nbsp;&nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">既然到此,顺便介绍一下内核空间映射情况。</span>

&nbsp;

&nbsp; &nbsp;&nbsp;内核空间如上图,分为直接内存映射区和高端内存映射区。其中直接内存映射区是指<span style="-ms-word-wrap: break-word;">3G</span>到<span style="-ms-word-wrap: break-word;">3G+896M</span>的线性空间,直接对应物理地址就是<span style="-ms-word-wrap: break-word;">0</span>到<span style="-ms-word-wrap: break-word;">896M</span>(前提是有超过<span style="-ms-word-wrap: break-word;">896M</span>的物理内存),其中<span style="-ms-word-wrap: break-word;">896M</span>是<span style="-ms-word-wrap: break-word;">high_memory</span>值,使用<span style="-ms-word-wrap: break-word;">kmalloc()/kfree()</span>接口操作申请释放;而高端内存映射区则是至超多<span style="-ms-word-wrap: break-word;">896M</span>物理内存的空间,它又分为动态映射区、永久映射区和固定映射区。动态内存映射区,又称之为<span style="-ms-word-wrap: break-word;">vmalloc</span>映射区或非连续映射区,是指<span style="-ms-word-wrap: break-word;">VMALLOC_START</span>到<span style="-ms-word-wrap: break-word;">VMALLOC_END</span>的地址空间,申请释放操作接口是<span style="-ms-word-wrap: break-word;">vmalloc()/vfree()</span>,通常用于将非连续的物理内存映射为连续的线性地址内存空间;而永久映射区,又称之为<span style="-ms-word-wrap: break-word;">KMAP</span>区或持久映射区,是指自<span style="-ms-word-wrap: break-word;">PKMAP_BASE</span>开始共<span style="-ms-word-wrap: break-word;">LAST_PKMAP</span>个页面大小的空间,操作接口是<span style="-ms-word-wrap: break-word;">kmap()/kunmap()</span>,用于将高端内存长久映射到内存虚拟地址空间中;最后的固定映射区,也称之为临时内核映射区,是指<span style="-ms-word-wrap: break-word;">FIXADDR_START</span>到<span style="-ms-word-wrap: break-word;">FIXADDR_TOP</span>的地址空间,操作接口是<span style="-ms-word-wrap: break-word;">kmap_atomic()/kummap_atomic()</span>,用于解决持久映射不能用于中断处理程序而增加的临时内核映射。

&nbsp; &nbsp;&nbsp;下图是根据个人的实验环境绘制的一张关于内核空间映射情况。

&nbsp;

 

&nbsp; &nbsp;&nbsp;PMD_MASK涉及的宏定义:

(file:/include/asm-generic/pgtable-nopmd.h)

#define PMD_SHIFT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PUD_SHIFT


#define PMD_SIZE&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1UL &lt;&lt; PMD_SHIFT)


#define PMD_MASK&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (~(PMD_SIZE-1))


(file:<span style="-ms-word-wrap: break-word;">/include/asm-generic/pgtable-nopud.h)</span>


#define PUD_SHIFT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PGDIR_SHIFT


(file:<span style="-ms-word-wrap: break-word;">arch/x86/include/asm/Pgtable-2level_types.h)</span>


#define PGDIR_SHIFT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 22
&nbsp; &nbsp;&nbsp;PMD_MASK计算结果是:<span style="-ms-word-wrap: break-word;">0xFFC00000</span>,其实是用于数据对齐而已。

&nbsp; &nbsp;&nbsp;已知<span style="-ms-word-wrap: break-word;">PAGE_OFFSET</span>默认的为<span style="-ms-word-wrap: break-word;">0xC0000000</span>,而<span style="-ms-word-wrap: break-word;">__VMALLOC_RESERVE</span>为:

unsigned int __VMALLOC_RESERVE = 128 << 20;

&nbsp; &nbsp;&nbsp;最后在个人的实验环境上,得出<span style="-ms-word-wrap: break-word;">MAXMEM_PFN</span>的值为<span style="-ms-word-wrap: break-word;">0x377fe</span>。

&nbsp; &nbsp;&nbsp;Linux是一个支持多硬件平台的操作系统,各种硬件芯片的分页并非固定的<span style="-ms-word-wrap: break-word;">2</span>级(页全局目录和页表),仅仅<span style="-ms-word-wrap: break-word;">Intel</span>处理器而言,就存在<span style="-ms-word-wrap: break-word;">3</span>级的情况(页全局目录、页中间目录和页表),而到了<span style="-ms-word-wrap: break-word;">64</span>位系统的时候就成了<span style="-ms-word-wrap: break-word;">4</span>级分页。所以<span style="-ms-word-wrap: break-word;">Linux</span>为了保持良好的兼容性和移植性,系统设计成了以下的<span style="-ms-word-wrap: break-word;">4</span>级分页模型,根据平台环境和配置的情况,通过将页上级目录和页中间目录的索引位设置为<span style="-ms-word-wrap: break-word;">0</span>,从而隐藏了页三级目录和页中间目录的存在。也就是为什么存在<span style="-ms-word-wrap: break-word;">PMD_SHIFT</span>、<span style="-ms-word-wrap: break-word;">PUD_SHIFT</span>和<span style="-ms-word-wrap: break-word;">PGDIR_SHIFT</span>,还有<span style="-ms-word-wrap: break-word;">pgtable-nopmd.h</span>、<span style="-ms-word-wrap: break-word;">pgtable-nopud.h</span>和<span style="-ms-word-wrap: break-word;">Pgtable-2level_types.h</span>的原因了。

<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp;&nbsp;由此管中窥豹,看到了</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">Linux</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">内存分页映射模型的存在和相关设计,暂且也就先了解这么多。</span>

<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp;&nbsp;分析宏是一件很乏味的事情,不过以小见大却是一件很有意思的事情。</span>


1. 【file:/arch/x86/mm/init_32.c】
2. /
3.  
4.   We have more RAM than fits into lowmem - we try to put it into
5.   highmem, also taking the highmem=x boot parameter into account:
6.  /
7. static void __init highmem_pfn_init(void)
8. {
9.     max_low_pfn = MAXMEM_PFN;
10.  
11.     if (highmem_pages == -1)
12.         highmem_pages = max_pfn - MAXMEM_PFN;
13.  
14.     if (highmem_pages + MAXMEM_PFN < max_pfn)
15.         max_pfn = MAXMEM_PFN + highmem_pages;
16.  
17.     if (highmem_pages + MAXMEM_PFN > max_pfn) {
18.         printk(KERN_WARNING MSG_HIGHMEM_TOO_SMALL,
19.             pages_to_mb(max_pfn - MAXMEM_PFN),
20.             pages_to_mb(highmem_pages));
21.         highmem_pages = 0;
22.     }
23. #ifndef CONFIG_HIGHMEM
24.     / Maximum memory usable is what is directly addressable /
25.     printk(KERN_WARNING "Warning only %ldMB will be used.\n", MAXMEM>>20);
26.     if (max_pfn > MAX_NONPAE_PFN)
27.         printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
28.     else
29.         printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
30.     max_pfn = MAXMEM_PFN;
31. #else / !CONFIG_HIGHMEM /
32. #ifndef CONFIG_HIGHMEM64G
33.     if (max_pfn > MAX_NONPAE_PFN) {
34.         max_pfn = MAX_NONPAE_PFN;
35.         printk(KERN_WARNING MSG_HIGHMEM_TRIMMED);
36.     }
37. #endif / !CONFIG_HIGHMEM64G /
38. #endif / !CONFIG_HIGHMEM /
39. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp;&nbsp;highmem_pfn_init()看起来很长,貌似很复杂,实际上仅仅是把</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">max_low_pfn</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">设置为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">MAXMEM_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,而</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">highmem_pages</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">设置为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">max_pfn - MAXMEM_PFN</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">,至于后面的几乎都是为了防止某些数据过大过小引起翻转而做的保障性工作。需要说明的是这里的</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">max_low_pfn作为</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">直接映射空间区的内存最大可用页帧号,并不是896M大小内存的页面数。896M只是定义高端内存的一个界限,至于直接映射内存大小只定义了不超过896M而已。</span>

&nbsp; &nbsp;&nbsp;此外还有一个准备操作,在<span style="-ms-word-wrap: break-word;">setup_arch()</span>函数中调用的页表缓冲区申请操作<span style="-ms-word-wrap: break-word;">early_alloc_pgt_buf()</span>:


1. 【file:/arch/x86/mm/init.c】
2. void init early_alloc_pgt_buf(void)
3. {
4.     unsigned long tables = INIT_PGT_BUF_SIZE;
5.     phys_addr_t base;
6.  
7.     base =
pa(extend_brk(tables, PAGE_SIZE));
8.  
9.     pgt_buf_start = base >> PAGE_SHIFT;
10.     pgt_buf_end = pgt_buf_start;
11.     pgt_buf_top = pgt_buf_start + (tables >> PAGE_SHIFT);
12. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 理解该函数前先看一下里面调用的</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">extend_brk()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">:</span>


1. 【file:/arch/x86/kernel/setup.c】
2. void __init extend_brk(size_t size, size_t align)
3. {
4.     size_t mask = align - 1;
5.     void ret;
6.  
7.     BUG_ON(_brk_start == 0);
8.     BUG_ON(align & mask);
9.  
10.     _brk_end = (_brk_end + mask) & ~mask;
11.     BUG_ON((char )(_brk_end + size) > __brk_limit);
12.  
13.     ret = (void )_brk_end;
14.     _brk_end += size;
15.  
16.     memset(ret, 0, size);
17.  
18.     return ret;
19. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 可以看到是从系统开启分页管理(</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">head_32.s</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">代码)中使用到的</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">__brk_base</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">保留空间申请一块内存出来,申请的空间大小为:</span>

#define INIT_PGT_BUF_SIZE        (6 * PAGE_SIZE)

&nbsp; &nbsp;&nbsp;也就是<span style="-ms-word-wrap: break-word;">24Kbyte</span>,同时将<span style="-ms-word-wrap: break-word;">_brk_end</span>标识的位置后移。里面涉及的几个全局变量作用:

pgt_buf_start:标识该缓冲空间的起始页框号;

pgt_buf_end:当前和<span style="-ms-word-wrap: break-word;">pgt_buf_start</span>等值,但是它用于表示该空间未被申请使用的空间起始页框号;


pgt_buf_top:则是用来表示缓冲空间的末尾,存放的是该末尾的页框号。
&nbsp; &nbsp;&nbsp;<span style="line-height: 1.5; -ms-word-wrap: break-word;">在</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">setup_arch()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">中,紧接着</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">early_alloc_pgt_buf()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">还有</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">reserve_brk()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">:</span>


1. 【file:/arch/x86/kernel/setup.c】
2. static void init reserve_brk(void)
3. {
4.     if (_brk_end > _brk_start)
5.         memblock_reserve(
pa_symbol(_brk_start),
6.                  _brk_end - _brk_start);
7.  
8.     / Mark brk area as locked down and no longer taking any
9.        new allocations /
10.     _brk_start = 0;
11. }
<span style="line-height: 1.5; -ms-word-wrap: break-word;">&nbsp; &nbsp; 其主要是用来将</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">early_alloc_pgt_buf()</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">申请的空间在</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">memblock</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">算法中做</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">reserved</span><span style="line-height: 1.5; -ms-word-wrap: break-word;">保留操作,避免被其他地方申请使用引发异常。</span>

[http://blog.chinaunix.net/uid-26859697-id-4592322.html](http://blog.chinaunix.net/uid-26859697-id-4592322.html)