《Linux0.11源码解读》理解(四) head之重新设置IDT/GDT

news/2024/10/20 16:07:37/

上节提到,现在cs:ip指向0地址,此处存储着作为操作系统核心代码的system模块,是由head.s和 main.c以及后面所有源代码文件编译链接而成。head.s(以下简称head)紧挨着main.c,我们先执行head。

重新设置内核栈

_pg_dir:
_startup_32:mov eax,0x10mov ds,axmov es,axmov fs,axmov gs,axlss esp,_stack_start

标号 _pg_dir表示页目录,意为在设置分页机制时,页目录会存放在这里,也会覆盖这里的代码。setup.s(以下简称setup)已经设置了gdt,现在要对段描述符重新设置包括ds/es/fs/gs。都被设置为0x10(00010000),在保护模式下即段选择子为2,指向数据段描述符。根据我们之前gdt表的内容,数据段的基地址是0,于是ds/es/fs/gs的基地址也是0。

lss 指令相当于让 ss:esp 这个栈顶指针(esp是sp的32为扩展),指向了 _stack_start 这个标号的位置(对比lds mem,reg:将段描述符mem的高位存储在 reg 寄存器的高位,而段描述符的低位存储在ds寄存器的低位)。当然之前在bootsec所设置的栈顶0x9ff00位置现在变成了0:stack_start:

// include/linux/mm.h
#define PAGE_SIZE 4096// kernel/sched.c
long user_stack [ PAGE_SIZE>>2 ] ;
struct {long * a;short b;} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };

其实从第三节得知我们已经在setup的内存(位于0x90200)设置了idt、gdt。现在则通过call setup_idt和setup_gdt重新设置位于head的内存(位于0x90000)的idt、gdt。为何重复设置?

因为位于setup的内存会在将来设计缓冲区时被覆盖,而且也不能将setup中的idt和gdt直接copy到现在的位置(在执行setup的时候copy无意义,因为如果先执行setup后移动system会覆盖掉copy的idt、gdt;如果先移动system后执行setup则会覆盖掉head内容),于是我们不得不在head重新设置它们。

设置IDT

即便是setup里面的idt也都是空的,现在由head程序正式设置。

setup_idt:lea edx,ignore_int  ;lea将ignore_int偏移地址(16bit)/而mov将第二操作数的内存内容 放入edxmov eax,00080000h   ;将段选择子0x0008置入eax高16位mov ax,dx           ;将ignore_int偏移地址置入eax低16位mov dx,8E00h        ;interrupt gate - dpl=0, presentlea edi,_idt        ;lea将_idt所代表偏移地址放入edimov ecx,256         ;cx用来计数,256次
rp_sidt:mov [edi],eax       ;[]寄存器间接寻址,表示eax的内容赋予“以edi的内容作为地址指针的”内存。mov [edi+4],edxadd edi,8dec ecxjne rp_sidtlidt fword ptr idt_descr   ;fword ptr是48位指针,用于远程跳转retidt_descr:dw 256*8-1    ;db字节(1 byte)类型,dw字类型(2 byte),dd双字类型(4 byte)dd _idt_idt:DQ 256 dup(0) ;伪操作,用来定义操作数占用的字节数

ignore_int作为默认中断处理程序函数地址,会放入中断描述符内。中段描述符结构如下:

这段代码意为将eax作为低32bit、edx作为高32bit填充一个中断描述符,并以cx作为计数器一共填充256次(共256项),以此来初始化整个IDT。最后通过lidt加载中断描述符至idtr让cpu识别。

重新设置GDT

setup_gdt:lgdt gdt_descrret
...
.align 2
.word 0
gdt_descr:.word 256*8-1		; gdtr内容是gdt的界限, 以及gdt所在的地址.long _gdt		    ; 每个gdt项占8byte, 一共256个gdt项, gdt总量2048byte.align 3
_gdt:	.quad 0x0000000000000000;   ;.quad为4word/8byte(等同.word 0,0,0,0). NULL desp.quad 0x00c09a0000000fff	; 代码段, 0fff=>4096, 4096*4096=16Mb.quad 0x00c0920000000fff	; 数据段, 除了基地址以外,其他同上.quad 0x0000000000000000	; TEMPORARY - don't us.fill 252,8,0			    ; space for LDT's and TSS's etc

对照gdt项所设置内容0x00c09a0000000fff的二进制和全局描述符格式:


g(granularity)粒度位如为0,段限长以1字节为单元;为1,段限长以4K字节为单元;dpl描述符特权级0和3级;p段存在位,该位为1指示描述符存在。于是0x00c09a00表示g为1,p为1,那么此代码段限长为4096*4K=16M。

重置了idt/gdt,接着又重新执行了一遍刚刚执行过的代码。为什么要重新设置这些段寄存器呢?因为修改了 gdt,所以要重新设置一遍,做个刷新,这样修改才能生效。

call setup_idt ;设置中断描述符表
call setup_gdt ;设置全局描述符表
mov eax,10h
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
lss esp,_stack_start

检验A20地址线是否打开

需要检验A20地址线是否打开,因为这会影响保护模式是否有效。这里通过如果没打开A20则0x100000会回滚到0x000000来判断,并不断循环直到A20开启为止:

	xor eax,eax         ; 异或,清空eax
1:	inc eax		        ; check that A20 really IS enabledmov 0x000000,eax	; loop forever if it isn'tcmp 0x100000,eaxje 1b               ; zf为0则跳转(通常搭配cmp,如源操作数和目标操作数相等,则跳转)

在检测到保护模式有效后,如果是486之前的cpu,会配备数学协处理器芯片以增强浮点计算能力。大概是先检查数学协处理器芯片是否存在。方法是修改控制寄存器CR0,在假设协处理器存在的情况下执行一个协处理器指令,如果出错的话则说明协处理器芯片不存在。这段代码不贴出来了,详细参见:flash-linux0.11-talk/head.s at main · dibingfa/flash-linux0.11-talk · GitHub

 开启分页机制,为进入main函数做准备

设置完协处理器后,将要开启分页机制,这是head的最后阶段也是执行main函数前的最后阶段。

...jmp after_page_tables
...
after_page_tables:push 0push 0push 0push L6push _mainjmp setup_paging
L6:jmp L6

可以看到将main函数参数、L6以及main函数地址都压栈,然后跳转到设置分页的标号。这些压栈是为了开启分页后执行main函数。

此外,即便main函数退出,程序也不会结束,因为我们看到程序到L6这边,是个死循环。


http://www.ppmy.cn/news/96574.html

相关文章

SAP-MM-采购申请-价值特性

采购申请审批在维护价值特性时要注意是抬头价值还是行价值,要确定选择哪个,配置时对应配置。 1、创建价值特性CT04 字段名称:CEBAN-GSWRT,和CEBAN-GFWRT 抬头总价值:CEBAN-GFWRT;如果选择的是抬头审批&am…

Unity刚体

1、Dynamic:动态类型 受重力和力的影响移动和旋转 Material: 物理材质,在刚体上设置了物理材质,如果子物体有碰撞器但是没有设置材质则会通用刚体的物理材质 如果不设置,将使用在Physics 2D窗口中设置的默认材质(Physi…

深入解析OSI七层协议:实现网络通信的基石

目录 引言:详细介绍1. 物理层(Physical Layer)2. 数据链路层(Data Link Layer)3. 网络层(Network Layer)4. 传输层(Transport Layer)5. 会话层(Session Layer…

AudioManager介绍

AudioManager介绍 AudioManager是Unity中的一个脚本类,用于管理游戏中的音频资源。它可以通过单例模式在整个游戏中访问,方便其他脚本类调用音频资源。 AudioManager方法 PlayBackgroundMusic(AudioClip clip) 播放背景音乐。 参数: cl…

python绘图工具matpoltlib的常用操作

目录 1.matplotlib概述2.风格设置3.条形图4.盒图5.直方图和散点图6.3D图7.pie图和布局8.Pandas与sklearn结合实例 1.matplotlib概述 Matplotlib 是一个用 Python 编程语言编写的、基于 NumPy 的开源数据可视化库。它提供了一套完整的兼容 MATLAB 的 API,支持各种常…

一个简单的基于C/S模型的TCP通信实例

1 TCP协议 1.1 概念 TCP是一种面向连接的、可靠的协议,有点像打电话,双方拿起电话互通身份之后就建立了连接,然后说话就行了,这边说的话那边保证听得到,并且是按说话的顺序听到的,说完话挂机断开连接。也…

数字前面填充0工具类

工具类 public class ParamUtil {//检查是否为数字private static final Pattern pattern Pattern.compile("[0-9]*");//检查是否为01-99之间的数字private static final Pattern pattern2 Pattern.compile("^([1-9]|0[1-9]|[1-9][0-9])$");//检查是否大…

[论文分享] jTrans: Jump-Aware Transformer for Binary Code Similarity

jTrans: Jump-Aware Transformer for Binary Code Similarity [ISSTA 2022] 二进制代码相似性检测(Binary code similarity detection, BCSD)在漏洞检测、软件构件分析、逆向工程等领域具有重要应用。最近的研究表明,深度神经网络(DNNs)可以理解二进制代码的指令或…