Linux0.11 源码中的内存分页机制

      学习Linux的源码,《深入linux 内核架构》这本书看起来就让人害怕,然后就想着看看早期的linux版本的源码,从网上查看资料发现linux0.11 这个版本有很多人拿来当成教学版本,而且也有很多的参考书以这个版本作为基础来讲解,于是就从这个版本看起,本文主要是总结一下head.s这个汇编源码中的内存分页机制的建立。  

      linux 大神关于这个的代码很少,但是完整的建立了内存分页的页目录和页表。

/*
 * I put the kernel page tables right after the page directory,
 * using 4 of them to span 16 Mb of physical memory. People with
 * more than 16MB will have to expand this.
 */
.org 0x1000
pg0:

.org 0x2000
pg1:

.org 0x3000
pg2:

.org 0x4000
pg3:

.org 0x5000
/*

setup_paging:
	movl $1024*5,%ecx		/* 5 pages - pg_dir+4 page tables */
	xorl %eax,%eax
	xorl %edi,%edi			/* pg_dir is at 0x000 */
	cld;rep;stosl
	movl $pg0+7,_pg_dir		/* set present bit/user r/w */
	movl $pg1+7,_pg_dir+4		/*  --------- " " --------- */
	movl $pg2+7,_pg_dir+8		/*  --------- " " --------- */
	movl $pg3+7,_pg_dir+12		/*  --------- " " --------- */
	movl $pg3+4092,%edi
	movl $0xfff007,%eax		/*  16Mb - 4096 + 7 (r/w user,p) */
	std
1:	stosl			/* fill pages backwards - more efficient :-) */
	subl $0x1000,%eax
	jge 1b
	xorl %eax,%eax		/* pg_dir is at 0x0000 */
	movl %eax,%cr3		/* cr3 - page directory start */
	movl %cr0,%eax
	orl $0x80000000,%eax
	movl %eax,%cr0		/* set paging (PG) bit */
	ret			/* this also flushes prefetch-queue */

   现在我们就从一个初学者的角度来解读这些汇编代码然后看看最后的效果。

	movl $1024*5,%ecx		/* 5 pages - pg_dir+4 page tables */
	xorl %eax,%eax
	xorl %edi,%edi			/* pg_dir is at 0x000 */
	cld;rep;stosl

 这一段代码是将从地址为0 开的20K 数据全部置位0. movl $1024*5,%ecx 是将ecx 寄存器设置为 1024*5. 然后将eax 和edi 寄存器全部设置为0x00000000(32位)。

cld;rep;stosl

这三条指令组合在一起用于在内存中填充数据。

  • cld:这条指令设置方向标志(Direction Flag)为0,意味着接下来的字符串操作将从低地址向高地址进行。
  • rep:这是一个前缀,它告诉处理器接下来的字符串操作应该重复执行,直到 %ecx 寄存器的值减到0为止。
  • stosl:这是一个字符串操作指令,它将 %eax 寄存器中的值(在这里是0,因为我们之前清零了 %eax)存储到由 %edi 寄存器指向的内存地址,并递增 %edi 的值(一次递增4)。

然后再往页目录中写入内容,$pg0+7 是0x00001007,$pg1+7 是0x00002007,$pg2+7 是0x00003007,$pg3+7 是0x00004007

	movl $pg0+7,_pg_dir		/* set present bit/user r/w */
	movl $pg1+7,_pg_dir+4		/*  --------- " " --------- */
	movl $pg2+7,_pg_dir+8		/*  --------- " " --------- */
	movl $pg3+7,_pg_dir+12		/*  --------- " " --------- */

 把0x00001007 转换成二进制 000000000000000000001 000000000111可以看出对应的是页表第一项。

后面这一段代码用来填充页表项的内容

	movl $pg3+4092,%edi
	movl $0xfff007,%eax		/*  16Mb - 4096 + 7 (r/w user,p) */
	std
1:	stosl			/* fill pages backwards - more efficient :-) */
	subl $0x1000,%eax
	jge 1b

 可以看到总共有4*1024个页表项需要写入值,std 设置为1,表示要从高地址往低地址来写。第一个写入的位置是页表三的最后一项,写入的内容是0x00fff007,写完之后写下一个,地址是$pg3+4092 -4,写入的内容是0x00ffe007,一直到eax的值为0.

 线性地址的通过页目录和页表来获取物理地址的位置。

 13M 位置的0000 0000 1101 0000 0000 0000 0000 0000 

页目录项0x3,页表项0x100,页内偏移地址0x0。

0x100 * 4k =256* 4 K =1M,而页表3 的起始地址是12M 所以就可以定位到13M的地址上面。

最后来设置页目录寄存器cr3 的值和设置启动分页处理标志位

	xorl %eax,%eax		/* pg_dir is at 0x0000 */
	movl %eax,%cr3		/* cr3 - page directory start */
	movl %cr0,%eax
	orl $0x80000000,%eax
	movl %eax,%cr0		/* set paging (PG) bit */

最后内存中的布局如下:

相关推荐

  1. Linux 内核分析】内存映射(mmap)机制原理

    2024-04-22 03:00:03       33 阅读
  2. Linux 内核分析】内存管理——Slab 分配器

    2024-04-22 03:00:03       30 阅读
  3. Linux 内核分析】物理内存组织结构

    2024-04-22 03:00:03       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-22 03:00:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-22 03:00:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-22 03:00:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-22 03:00:03       20 阅读

热门阅读

  1. LeetCode 3.无重复字符发最长字串

    2024-04-22 03:00:03       14 阅读
  2. 提高写作效率:ChatGPT写作攻略

    2024-04-22 03:00:03       17 阅读
  3. 修改Ubuntu的镜像源为清华镜像源

    2024-04-22 03:00:03       14 阅读
  4. lv_table

    2024-04-22 03:00:03       12 阅读
  5. 关于UAC标准音频数据传输端点的最大包长问题

    2024-04-22 03:00:03       13 阅读
  6. 算法:堆(优先队列)

    2024-04-22 03:00:03       14 阅读
  7. Beego框架学习

    2024-04-22 03:00:03       15 阅读
  8. 蓝桥杯刷题-包子凑数

    2024-04-22 03:00:03       16 阅读
  9. 好数(蓝桥杯)

    2024-04-22 03:00:03       13 阅读