linux0.12 head.s代码解析

  1. 重新设置IDT和GDT,为256个中断门设置默认的中断处理函数
  2. 检查A20地址线是否启用
  3. 设置数学协处理器
  4. 将main函数相关的参数压栈
  5. 设置分页机制,将页表映射到0~16MB的物理内存上
  6. 返回main函数执行

源码详细注释如下:

/**  linux/boot/head.s**  (C) 1991  Linus Torvalds*//**  head.s contains the 32-bit startup code.** NOTE!!! Startup happens at absolute address 0x00000000, which is also where* the page directory will exist. The startup code will be overwritten by* the page directory.*/
.text
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
_pg_dir:
startup_32:
# 段寄存器先指向setup.S中的数据段movl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fsmov %ax,%gslss _stack_start,%esp # 设置栈指针和栈段寄存器
# 设置IDT和GDTcall setup_idtcall setup_gdt
# 重新加载段寄存器和栈movl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fsmov %ax,%gslss _stack_start,%esp
# 检查A20地址线是否启用xorl %eax,%eax
1:	incl %eax            # check that A20 really IS enabledmovl %eax,0x000000   # loop forever if it isn'tcmpl %eax,0x100000je 1b
/** NOTE! 486 should set bit 16, to check for write-protect in supervisor* mode. Then it would be unnecessary with the "verify_area()"-calls.* 486 users probably want to set the NE (#5) bit also, so as to use* int 16 for math errors.*/movl %cr0,%eax          # check math chipandl $0x80000011,%eax   # 清楚其他位,保留PG PE ET位orl $2,%eax             # set MP位,表示启用数学协处理器movl %eax,%cr0          # 写回CR0寄存器call check_x87jmp after_page_tables# 设置协处理器
check_x87:fninit                  # 初始化协处理器fstsw %ax               # 取协处理器状态字到ax寄存器cmpb $0,%alje 1f                   # 如果协处理器状态字为0,则有协处理器,跳转1movl %cr0,%eaxxorl $6,%eax            # 清除MP、设置EM位movl %eax,%cr0ret
.align 2
1:	.byte 0xDB,0xE4         # 等价于fsetpm,用于设置协处理器模式retsetup_idt:
/** %eax:* 位31-16: 0x0008 (段选择子)* 位15-0:  ignore_int地址的低16位* %edx:* 位31-16: 0x8E00 (中断门属性)* 位15-0:  ignore_int地址的高16位
*/lea ignore_int,%edxmovl $0x00080000,%eaxmovw %dx,%axmovw $0x8E00,%dxlea _idt,%edi          # edi指向IDT的基地址mov $256,%ecx          # 256个中断门
rp_sidt:movl %eax,(%edi)movl %edx,4(%edi)addl $8,%edi           # 移动到下一个中断门描述符dec %ecx               # 循环计数器减1jne rp_sidtlidt idt_descr         # 加载IDT描述符ret/**  setup_gdt**  This routines sets up a new gdt and loads it.*  Only two entries are currently built, the same*  ones that were built in init.s. The routine*  is VERY complicated at two whole lines, so this*  rather long comment is certainly needed :-).*  This routine will beoverwritten by the page tables.*/
setup_gdt:lgdt gdt_descrret/** 物理地址    内容          大小      用途* 0x0000   页目录(_pg_dir)  4KB      页目录表* 0x1000   页表0(pg0)      4KB       映射0-4MB物理内存* 0x2000   页表1(pg1)      4KB       映射4-8MB物理内存  * 0x3000   页表2(pg2)      4KB       映射8-12MB物理内存* 0x4000   页表3(pg3)      4KB       映射12-16MB物理内存* 0x5000   软盘缓冲区      4KB       软盘DMA缓冲区*/
.org 0x1000
pg0:
.org 0x2000
pg1:
.org 0x3000
pg2:
.org 0x4000
pg3:
.org 0x5000
/** tmp_floppy_area is used by the floppy-driver when DMA cannot* reach to a buffer-block. It needs to be aligned, so that it isn't* on a 64kB border.*/
_tmp_floppy_area:.fill 1024,1,0after_page_tables:pushl $0pushl $0pushl $0               # 这些是main函数的参数pushl $L6              # 如果main函数决定返回,则返回地址为L6pushl $_main           # main函数地址压栈jmp setup_paging       # 跳转设置分页机制
L6:jmp L6                 # main应该永远不会返回,以防万一,我们不知道会发生什么# 默认中断处理程序
int_msg:.asciz "Unknown interrupt\n\r"
.align 2
ignore_int:pushl %eaxpushl %ecxpushl %edxpush %dspush %espush %fsmovl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fspushl $int_msgcall _printkpopl %eaxpop %fspop %espop %dspopl %edxpopl %ecxpopl %eaxiret.align 2
setup_paging:
# 清零页目录和页表区域movl $1024*5,%ecxxorl %eax,%eaxxorl %edi,%edicld;rep;stosl
# 设置页目录项movl $pg0+7,_pg_dirmovl $pg1+7,_pg_dir+4movl $pg2+7,_pg_dir+8movl $pg3+7,_pg_dir+12
# 通过循环将页表映射到物理内存,从高地址向低地址填充movl $pg3+4092,%edimovl $0xfff007,%eaxstd
1:	stoslsubl $0x1000,%eaxjge 1bxorl %eax,%eaxmovl %eax,%cr3          # 设置CR3寄存器,指向页目录的起始地址movl %cr0,%eaxorl $0x80000000,%eaxmovl %eax,%cr0          # 启用分页机制ret                     # 由于之前压栈了main,返回main函数执行.align 2
.word 0
idt_descr:.word 256*8-1		# idt contains 256 entries.long _idt
.align 2
.word 0
gdt_descr:.word 256*8-1		# so does gdt (not that that's any.long _gdt		# magic number, but it works for me :^).align 3
_idt:	.fill 256,8,0		# idt is uninitialized_gdt:	.quad 0x0000000000000000	/* NULL descriptor */.quad 0x00c09a0000000fff	    /* 内核代码段 16Mb */.quad 0x00c0920000000fff	    /* 内核数据段 16Mb */.quad 0x0000000000000000	    /* 暂时未使用 */.fill 252,8,0			        /* space for LDT's and TSS's etc */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97842.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Maven动态控制版本号秘籍:高效发包部署,版本管理不再头疼!

作者:唐叔在学习 专栏:唐叔的Java实践 关键词:Maven版本控制、versions插件、动态版本号、持续集成、自动化部署、Java项目管理 摘要:本文介绍如何使用Maven Versions插件动态控制项目版本号和依赖组件版本号,实现无需…

简述:普瑞时空数据建库软件(国土变更建库)之一(变更预检查部分规则)

简述:普瑞时空数据建库软件(国土变更建库)之一(变更预检查部分规则) 主要包括三种类型:常规检查、行政区范围检查、20X异常灭失检查 本blog地址:https://blog.csdn.net/hsg77

shell中命令小工具:cut、sort、uniq,tr的使用方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、cut —— 按列或字符截取1. 常用选项2. 示例二、sort —— 排序(默认按行首字符升序)1. 常用选项常用 sort 命令选项三、uniq —— 去…

【Linux】Linux开发必备:Git版本控制与GDB调试全指南

前言:在Linux开发流程中,版本控制与程序调试是保障项目稳定性和开发效率的两大核心环节。Git作为当前最主流的分布式版本控制系统,能高效管理代码迭代、追踪修改记录并支持多人协同开发;GDB(GNU调试器)是Li…

实现 TypeScript 内置工具类型(源码解析与实现)

目标读者:已经熟悉 TypeScript 基础语法、泛型、条件类型的同学。本文按常见工具类型的分类与顺序实现并解释 Partial、Required、Readonly、Pick、Omit、Record、Exclude、Extract、NonNullable、ReturnType、Parameters、ConstructorParameters、InstanceType、Th…

Spring Boot + Nacos 配置中心示例工程

1️⃣ 工程结构 nacos-demo├── pom.xml└── src├── main│ ├── java│ │ └── com.example.nacosdemo│ │ ├── NacosDemoApplication.java│ │ ├── config│ │ │ └── AppProperties.java│ │ └── cont…

(二)文件管理-基础命令-pwd命令的使用

文章目录1. 命令格式2. 基本用法3. 高级用法4. 注意事项1. 命令格式 pwd [OPTION]...[OPTION]: 可选选项,用于改变命令的默认行为。最主要的两个选项是 -L 和 -P。它不需要任何参数(如文件名或目录名) 2. 基本用法 用法:pwd 是…

Leetcode_202.快乐数_三种方法解决(普通方法解决,哈希表解决,循环链表的性质解决_快慢指针)

目录第一种方法:暴力解法暴力ac代码:第二种方法:哈希表哈希表ac代码:第三种方法:根据循环链表的性质(快慢指针)第一种方法:暴力解法 最暴力的思路就是直接使用循环往下一直计算,这样特别浪费时间&#xff…

代码随想录刷题Day48

这次博客主要是对做过的关于二叉树系列的题目进行整理和分类。二叉树,要处理整个树,一般少不了遍历。遍历主要可以分为:递归系列、层序遍历。如果不遍历的话,那就是处理特殊的树了,比如完全二叉树。递归系列基本的递归…

汽车工装结构件3D扫描尺寸测量公差比对-中科米堆CASAIM

汽车制造过程中,工装结构件的尺寸精度对整车装配质量和生产进度有重要影响。传统测量工具如卡尺和三坐标测量机采用接触式工作方式,检测过程耗时较长,对于具有复杂曲面特征的工件,难以全面获取尺寸数据。激光三维扫描技术改变了传…

Docker Pull 代理配置方法

本文介绍通过网络代理加速Docker镜像拉取的方法。 配置方法 当执行docker pull从Docker Hub 拉取镜像时,其网络连接由守护进程docker daemon进行维护。 要修改其代理设置,可配置其systemd服务,步骤如下: (1&#xf…

机电装置:从基础原理到前沿应用的全方位解析

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! 1 机电装置的基本概念与发展历程 机电装置(Mechatronic D…

《SVA断言系统学习之路》【03】关于布尔表达式

序列中使用的表达式基于其所含变量的采样值进行评估。表达式评估的结果为布尔值,其解释方式与过程性if语句条件中的表达式完全相同:若表达式计算结果为X、Z 或 0,则被解释为假;否则即为真。但是,对可出现在并发断言中的…

指针高级(2)

6.数组指针#include <stdio.h> int main() {/*练习&#xff1a;利用指针遍历数组*///1.定义数组int arr[] { 10,20,30,40,50 };int len sizeof(arr) / sizeof(int);//2.获取数组的指针//实际上获取的&#xff1a;数组的首地址int* p1 arr;int* p2 &arr[0];printf…

如何高效记单词之:抓住首字母——以find、fund、fond、font为例

find、fund、fond、font这几个单词&#xff0c;你都认识吗&#xff1f;这几个单词&#xff0c;意思大体如下&#xff1a; find v.找到&#xff1b;发现fund n.基金fond a.喜欢的&#xff1b;喜爱的&#xff1b;深情的font n.字体&#xff0c;字型&#xff0c;字形 这几个单词在…

Ubuntu下把 SD 卡格式化为 FAT32

在 Ubuntu 下把 SD 卡格式化为 FAT32&#xff0c;按下面做&#xff08;会抹掉整卡数据⚠️&#xff09;&#xff1a; 1) 找到你的 SD 卡设备名 lsblk -p记下整盘设备&#xff0c;比如 /dev/sdb&#xff08;USB 读卡器常见&#xff09;或 /dev/mmcblk0&#xff08;内置读卡器&am…

涉私数据安全与可控匿名化利用机制研究(上)

文章目录前言一、涉私数据的概述及分类&#xff08;一&#xff09;涉私数据的“知情同意原则”&#xff08;二&#xff09;涉私数据的分类二、涉私数据可控匿名化利用机制&#xff08;一&#xff09;数据产品与涉私数据的利用形式&#xff08;二&#xff09;通过可信数据空间受…

Redis 的跳跃表:像商场多层导航系统一样的有序结构

目录 一 、从 "超市货架" 的痛点看跳跃表的价值 1.1、跳跃表与商场导航系统的结构对应 1. 1.1、zskiplistNode&#xff1a;带导航标记的 "商品"&#xff08;跳跃表节点&#xff09; 1.1.1.1、level []&#xff1a;商品上的多层导航标记 1.1.1.2、back…

小程序点击之数据绑定

<return /><view class"all-wrap" style"padding-top:{{topHeight}}px;"><view class"my-title">我的收藏</view><scroll-viewclass"collect-list-container"scroll-yscroll-top"{{scrollTop}}"…

数据结构——顺序表和单向链表(2)

目录 前言 一、单向链表 1、基本概念 2、单向链表的设计 &#xff08;1&#xff09;节点设计 &#xff08;2&#xff09;初始化空单向链表 &#xff08;3&#xff09;、初始化数据节点 &#xff08;4&#xff09;数据节点 &#xff08;5&#xff09;判断链表是否为空 …