Linux-0.11 boot目录head.s详解

这篇具有很好参考价值的文章主要介绍了Linux-0.11 boot目录head.s详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux-0.11 boot目录head.s详解

模块简介

在head.s中,操作系统主要做了如下几件事:

  • 重新设置中断描述符和全局描述符
  • 检查A20地址线是否开启
  • 检查数学协处理器
  • 初始化页表并开启分页
  • 跳转到main函数执行

过程详解

重新设置IDT和GDT

在setup.s中我们已经设置过了IDT和GDT, 为什么还要再设置一遍?

因为setup.s中设置的IDT和GDT后面会被覆盖,因此在head.S中会重新设置一遍。

startup_32:
	movl $0x10,%eax
	mov %ax,%ds
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs
	lss stack_start,%esp
	call setup_idt     !设置中断
	call setup_gdt     !设置全局描述符表
	movl $0x10,%eax		# reload all the segment registers
	mov %ax,%ds		# after changing gdt. CS was already
	mov %ax,%es		# reloaded in 'setup_gdt'
	mov %ax,%fs
	mov %ax,%gs
	lss stack_start,%esp

中断门描述符的格式如下所示:

Linux-0.11 boot目录head.s详解

检查A20地址线是否开启

下面用于检测A20地址线是否已经开启。

	xorl %eax,%eax
1:	incl %eax		# check that A20 really IS enabled
	movl %eax,0x000000	# loop forever if it isn't
	cmpl %eax,0x100000
	je 1b

检查数学协处理器

下面用于检查数学协处理器芯片是否存在

	movl %cr0,%eax		# check math chip
	andl $0x80000011,%eax	# Save PG,PE,ET
/* "orl $0x10020,%eax" here for 486 might be good */
	orl $2,%eax		# set MP
	movl %eax,%cr0
	call check_x87
	jmp after_page_tables

/*
 * We depend on ET to be correct. This checks for 287/387.
 */
check_x87:
	fninit     !向协处理发出初始化命令
	fstsw %ax  !取协处理器状态字到ax寄存器中
	cmpb $0,%al
	je 1f			/* no coprocessor: have to set bits */
	movl %cr0,%eax
	xorl $6,%eax		/* reset MP, set EM */
	movl %eax,%cr0
	ret

初始化页表并开启分页

下面这里将进行页表的安装,安装的过程参考下面这张图:
Linux-0.11 boot目录head.s详解

after_page_tables:
	pushl $0		# These are the parameters to main :-)
	pushl $0
	pushl $0
	pushl $L6		# return address for main, if it decides to.
	pushl $main
	jmp setup_paging

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
	cld
	xorl %eax,%eax		 !设置页目录表基址寄存器cr3的值
	movl %eax,%cr3		
	movl %cr0,%eax       !设置启动使用分页处理
	orl $0x80000000,%eax
	movl %eax,%cr0		/* set paging (PG) bit */
	ret			/* this also flushes prefetch-queue */

跳转到main函数执行

在setup_paging执行完毕之后,会通过ret返回,ret指令会将栈顶的内容弹出到PC指针中去执行。此时esp指向的位置存放的是main函数的地址。因此接下来会执行main函数。

注意到在将main入栈时,还一同入栈了一些其他参数

	pushl $0		# These are the parameters to main :-)
	pushl $0
	pushl $0
	pushl $L6

这里就需要回顾一下c语言的调用规约,如下图所示:

Linux-0.11 boot目录head.s详解

因此这里可以得到L6是main函数的返回值。立即数0,0,0将会被作为main函数的入参。

接下来再看下面的代码就很清晰了,实际就是在建立好页表的映射关系后,就开始跳转到main函数去执行了(init/main.c)。

after_page_tables:
	pushl $0		# These are the parameters to main :-)
	pushl $0
	pushl $0
	pushl $L6		# return address for main, if it decides to.
	pushl $main
	jmp setup_paging

setup_paging:
   ...
   ret

Q & A

setup_paging在建立页表时会将head.s的部分代码覆盖,怎么保证不会把正在执行的代码覆盖?

可以通过反汇编查看一下system模块的内存分布

objdump -d tools/system

如下所示:

00000000 <pg_dir>:
       0:	b8 10 00 00 00       	mov    $0x10,%eax
       5:	8e d8                	mov    %eax,%ds
	   ...
0000005a <check_x87>:
      5a:	db e3                	fninit 
      5c:	9b df e0             	fstsw  %ax
      5f:	3c 00                	cmp    $0x0,%al
	  ...
00000071 <setup_idt>:
      71:	8d 15 28 54 00 00    	lea    0x5428,%edx
      77:	b8 00 00 08 00       	mov    $0x80000,%eax
	  ...
0000008e <rp_sidt>:
      8e:	89 07                	mov    %eax,(%edi)
      90:	89 57 04             	mov    %edx,0x4(%edi)
	  ...
000000a1 <setup_gdt>:
      a1:	0f 01 15 b2 54 00 00 	lgdtl  0x54b2
      a8:	c3                   	ret    
	...
00001000 <pg0>:
	...

00002000 <pg1>:
	...

00003000 <pg2>:
	...

00004000 <pg3>:
	...
00005000 <tmp_floppy_area>:
	...
00005400 <after_page_tables>:
    5400:	6a 00                	push   $0x0
    5402:	6a 00                	push   $0x0
	...
00005412 <L6>:
    5412:	eb fe                	jmp    5412 <L6>
00005414 <int_msg>:
    5414:	55                   	push   %ebp
    5415:	6e                   	outsb  %ds:(%esi),(%dx)
	...
00005428 <ignore_int>:
    5428:	50                   	push   %eax
    5429:	51                   	push   %ecx
	...
0000544e <setup_paging>:
    544e:	b9 00 14 00 00       	mov    $0x1400,%ecx
    5453:	31 c0                	xor    %eax,%eax
    5455:	31 ff                	xor  
	...
000054aa <idt_descr>:
    54aa:	ff 07                	incl   (%edi)
    54ac:	b8 54 00 00 00       	mov    $0x54,%eax
	...

000054b2 <gdt_descr>:
    54b2:	ff 07                	incl   (%edi)
    54b4:	b8                   	.byte 0xb8
    54b5:	5c                   	pop    %esp
	...

000054b8 <idt>:
	...

00005cb8 <gdt>:
	...
    5cc0:	ff 0f                	decl   (%edi)

可以看到代码标号setup_page的起始地址是0000544e,而内存页表和页目录表的地址范围是0x0000-0x5000。因此当程序执行到setup_page时,将建立页目录表和页表, 这将会覆盖0x0000-0x5000的部分代码,即pg_dir,check_x87,setup_idt,rp_sidt,setup_gdt, 并不会覆盖到setup_page的代码,head.s在代码的分布计算上确实是费了一番功夫。


文中如有表达不正确之处,欢迎大家与我交流, 微信codebuilding.文章来源地址https://www.toymoban.com/news/detail-461982.html

到了这里,关于Linux-0.11 boot目录head.s详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux 0.11: 从开机到执行shell

    参考闪客的系列,将开机到执行shell的整个过程浓缩成本文。 https://github.com/dibingfa/flash-linux0.11-talk 当按下开机键的那一刻,在主板上提前写死的固件程序  BIOS  会将硬盘中 启动区的 512 字节 的数据,原封不动复制到 内存中的 0x7c00  这个位置,并跳转到那个位置进行执行。

    2024年04月13日
    浏览(19)
  • 操作系统实验 2.3系统调用:linux-0.11-lab “为版本0内核增加一个系统调用getjiffies” 和 “在用户程序中使用新增的系统调用”

    打开 vscode ,在如图所示位置打开 ~/os/linux-0.11-lab/0 文件夹 1.定义getjiffies系统调用 题目中给的提示:进入到 unistd.h 文件中 阅读代码,可以发现上图划线处有个系统调用名为 getpid :返回当前进程号——这与我们期望实现的功能类似:通过系统调用返回jiffies值。 于是此时希望

    2023年04月08日
    浏览(83)
  • 【Linux0.11代码分析】04 之 head.s 启动流程

    系列文章如下: 系列文章汇总:《【Linux0.11代码分析】之 系列文章链接汇总(全)》 . 1.《【Linux0.11代码分析】01 之 代码目录分析》 2.《【Linux0.11代码分析】02 之 bootsect.s 启动流程》 3.《【Linux0.11代码分析】03 之 setup.s 启动流程》 4.《【Linux0.11代码分析】04 之 head.s 启动流程

    2024年02月03日
    浏览(29)
  • windows一键安装redis7.0.11

    下载地址: https://gitcode.net/zengliguang/windows_redis7.0.11_offline_install.git   使用git进行进行clone下载   在电脑桌面或者其他文件夹下 ,鼠标右键点击  选择git clone  ,下图中url为下载地址,Directory为本地存储路径,点击ok开始下载 如下图所示已成功下载   双击 redis-install-win.ba

    2024年02月08日
    浏览(35)
  • 【公告】BSV节点软件发布最新升级版本v1.0.11

    发表时间:2022年4月21日 信息来源:bitcoinsv.io 本次新发布的v1.0.11是基于v1.0.10版的推荐升级版本,对交易费的配置选项进行了一些更改,并修复了一些错误。  本次发布的软件里,相较此前版本的变更内容具体如下: 对以下配置选项进行了更名  -blockmintxfee 默认禁用 Bloom 过滤

    2023年04月08日
    浏览(74)
  • 阿里巴巴开源Chat2DB v1.0.11 初体验

    作为一名阿里巴巴开源项目的拥护者,从Chat2DB开源至今都有关注这个开源项目,因为之前的版本还存在较多BUG,暂时就没有分享,目前升级到 v1.0.11 版本后,我来谈谈我个人的一个使用感受 Chat2DB 是一款有开源免费的多数据库客户端工具,支持windows、mac本地安装,也支持服

    2024年02月09日
    浏览(47)
  • springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题

    ide2021 jdk17 springboot3.0.11-SNAPSHOT 在使用springboot3写完一个项目后,想快速生成一篇接口文档,供自己观看。在网上冲浪一段时间后,发现使用Swagger文档比较合适,通过少量的注解来完成一篇复杂的文档。说干就干,直接cope网上的资料写一个demo来用,发现项目无法正常启动。在

    2024年02月04日
    浏览(50)
  • Docker-Compose编排Nginx1.25.1+PHP7.4.33+Redis7.0.11环境

    实践说明:基于RHEL7(CentOS7.9)部署docker环境(23.0.1、24.0.2),编排也可应用于RHEL7-9(如AlmaLinux9.1),但因为docker的特性,适用场景是不限于此的。 文档形成时期:2017-2023年 因系统或软件版本不同,构建部署可能略有差异,但本文未做细分,对稍有经验者应不存在明显障碍。 因软件

    2024年01月22日
    浏览(43)
  • Linux /dev目录详解和Linux系统各个目录的作用

    在linux下,/dev目录是很重要的,各种设备都在下面。下面简单总结一下: dev是设备(device)的英文缩写。 /dev这个目录对所有的用户都十分重要。 因为在这个目录中包含了所有Linux系统中使用的外部设备。但是这里并不是放的外部设备的驱动程序,这一点和 windows ,dos操作系统不

    2024年04月11日
    浏览(36)
  • (三) Linux基本目录详解

    (一) Linux入门概述 (二) Linux环境搭建 (三)Linux基本目录详解 了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只管重要,下面我们就开始了解一下linux目录结构的相关知识。

    2024年02月04日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包