linux0.11 80386段
最近在看linux0.11源码,对其中的进程调度查了一些资料,《80386汇编语言精要》这本书写的非常好,对理解帮助很大,建议大家看一下,主要是两方面的知识:
- GDT\IDT与运行有什么关系?
- 80386有三种运行模式:实模式,保护模式,兼容8086模式
- linux0.11中具体是如何实现的
GDT\IDT与运行有什么关系?
先弄清楚以下这几个寄存器的作用(作用就是为了寻址)。
- GDT:该表地址存在GDTR寄存器里
全局描述符表 GDT ( Global Descriptor Table) , 除了任务门、中断门和陷井门描述符外 , 包含着系统中所有任务都可用的那些描述符。它的第一个 8 字节位置 没有使用。其中可以存放如下几种不同的描述符:
- 门:为什么task切换要使用软中断
门是用来控制访问在目标码段的入口点。有调用门、任务门、中断门和陷井门四种。所谓中断就是用于处理外部发生的突发事件, 陷井是一种特殊的中断, 用户定的软件中断其实就是陷井。调用门主要用于将程序控制转换到一个更高的特权级(数字低) , 任务门用于切换任务, 它只能涉及任务状态段。中断门和陷井门用于中断处理, 其中的地址是指向中断或陷井处理子程序起点的指针, 中断门禁止中断( IF = 0) , 而陷井门并不禁止。
- IDT:该表地址存在IDTR寄存器里
中断描述符表 IDT ( Interrupt Descriptor Table) , 可以包含 256 个描述符 , 每个描述符为 8 个字节。IDT 中只能包含任务门、中断门和陷井门描述符 , 虽然它最长也可以为 64K 字节 , 但只能存取 2K 字节以内的描述符 , 即 256 个。它最少为 256 个字节 ,因为 Intel 公司保留了 32 个中断描述符供自己使用。规定这些数字都是为了和早期的机器兼容。
- LDT:
局部描述符表 LDT ( Local Descriptor Table) , 包含了与一个给定任务有关的描述符 , 每一个任务都有一个各自的 LDT。有了 LDT, 就可以使给定任务的码、数据与别的任务相隔离。 LDT 中的描述符都在 GDT 中 , 所以 , 不同的任务可以有相同的描述符 , 这样就可以共享全局数据和代码。段描述符:就是存在GDT中的项
TSS:在 GDT
所谓任务状态段 TSS ( Task State Segment) , 就是一个特殊的固定格式的段 , 它包含了一个任务和与之相链接的允许嵌套的任务的所有状态信息!这个段在task切换中非常重要,我后面再分析。当任务状态段描述符所描述的任务正在执行时, 它就是类型B, 否则就置成类型9。TSS 就由任务状态寄存器TR 来标识,TR有16位可见+64位不可见,16位可见就是段选择子,相当于GDT中的索引,TR通过可见的16位找到TSS。执行IRET 时, 控制返回到原来的任务, 当前的任务状态则被保存到TSS 中, 并从原有任务的TSS 中恢复原有任务的状态。
- 段选择子:(放在段寄存器里,80386中有6个(即CS,SS,DS,ES,FS,GS)16位的段寄存器)
在实模式下 , 段寄存器存储的是真实的段地址 , 在保护模式下 , 16 位的段寄存器无法放下 32 位段地址 , 因此 , 它们被称为选择器 , 即起选择描符述表中的描述符的作用。这样 , 就把描述符中的 32 位段地址做为实际的段地址。
80386有三种运行模式:实模式,保护模式,兼容8086模式。
兼容8086模式很好理解!每种模式下寄存器的内容均有不同的意义,实模式与保护模式主要为了通过硬件的设计添加错误检查。你可以设计的程序只运行在实模式(实模式是16位,保护模式是32位)所有的地址都是硬件地址,随便一个指针错误都会造成死机,当然结果就是系统很容易崩溃!linux中setup.s最后几句就是进入保护模式。
# Well, now's the time to actually move into protected mode. To make # things as simple as possible, we do no register set-up or anything, # we let the gnu-compiled 32-bit programs do that. We just jump to # absolute address 0x00000, in 32-bit protected mode. #mov $0x0001, %ax # protected mode (PE) bit #lmsw %ax # This is it! mov %cr0, %eax # get machine status(cr0|MSW) bts $0, %eax # turn on the PE-bit mov %eax, %cr0 # protection enabled |
进入保护模式后,软件使用逻辑地址访问时,硬件可以通过段描述符检查是否溢出。
例如:若给定一个逻辑地址是 a:b ,根据逻辑地址的a(段选择符)的T1位确定是选择GDT还是LDT。
a若是T1位选择GDT,根据GDTR找到GDT的基址,根据a的 3~15位确定它的段描述符X在GDT中的位置(GDTR即基址+a的3-15bit即相对位置):确定段描述符X,再根据段描述符提取出其中包含的段基址信息,段基址+b(段内偏移),最终确定线性地址。
a若是T1位选择LDT,根据GDTR找到GDT的基址,根据LDTR的高13位确定它的LDTX描述符在GDT中的位置(GDTR基址+LDTR13bit即相对位置):确定LDTX描述符。LDTX描述符可以确定LDT的基址(LDTX描述符确定LDT表在内存中的起始位置),再根据段选择符a确定的相对位置,可以确定LDT中的私有段描述符Y。接下来同上面的:再根据段描述符提取出其中包含的段基址信息,段基址+b(段内偏移),最终确定线性地址。
linux0.11中具体是如何实现的?
在setup.s中有加载idt与gdt,指令如下:
lidt idt_48 # load idt with 0,0 |
lidt与lgdt操作数是48位,6 字节操作数装入全局描述符表寄存器IDTR与GDTR。
setup.s代码中的定义如下:需要注意的是此时系统还处于实模式16位操作。
gdt: .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb) .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb) idt_48: gdt_48: |
然后通过以下指令进入保护模式并跳转。跳转指令是ljmp。
#mov $0x0001, %ax # protected mode (PE) bit #lmsw %ax # This is it! mov %cr0, %eax # get machine status(cr0|MSW) bts $0, %eax # turn on the PE-bit mov %eax, %cr0 # protection enabled # segment-descriptor (INDEX:TI:RPL) .equ sel_cs0, 0x0008 # select for code segment 0 ( 001:0 :00) ljmp $sel_cs0, $0 # jmp offset 0 of code segment 0 in gdt |
进入保护模式之后第一件事是什么,当然是设置堆栈。这个时候再回头看head.s的开头就更清楚了,之前的boot分析其实还不是很懂这里为什么要lss两次。如果第一次lss不设置,那么这个堆栈寄存器esp根本就没有初始化。
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 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 |
linux0.11 80386段相关推荐
- 一站式linux0.11内核head.s代码段图表详解
阅读本文章需要的基础: 计算机组成原理:针对8086,80386CPU架构的计算机硬件体系要有清楚的认知,我们都知道操作系统是用来管理硬件的,那我们就要对本版本的操作系统所依赖的硬件体系有系统的了解, ...
- setup.s 解读——Linux-0.11 剖析笔记(三)
题目:setup.s 解读--Linux-0.11 剖析笔记(三) 更新记录 版本 时间 修订内容 1.0 2018-4-14 增加了"获取显示模式"这一节,AL取值的表格 2.0 ...
- setup.s 分析—— Linux-0.11 学习笔记(二)
更新记录 版本 时间 修订内容 1.0 2018-4-14 增加了"获取显示模式"这一节,AL取值的表格 标题: setup.s 分析-- Linux-0.11 学习笔记(二) 老 ...
- Linux0.11内核剖析--内核体系结构
一个完整可用的操作系统主要由 4 部分组成:硬件.操作系统内核.操作系统服务和用户应用程序,如下图所示: 用户应用程序是指那些字处理程序. Internet 浏览器程序或用户自行编制的各种应用程序: ...
- linux0.11磁盘映像制作及其剩余程序阅读注释笔记
[ 1] linux0.11引导程序阅读注释. [ 2] linux0.11由实模式进入保护模式程序阅读注释 . [ 3] linux0.11护模式初始化程序阅读注释. [ 4] linux0.11主 ...
- Linux0.11内核引导启动过程概述
Linux0.11仅支持x86架构.它的内核引导启动程序在文件夹boot内,共有三个汇编代码文件.按照启动流程依次是: (1)bootsect.s.boot是启动引导的意思,sect即sector,是 ...
- c 取地址 虚拟地址 物理地址_通过linux0.11源码理解进程的虚拟地址、线性地址、物理地址...
进程的地址有三种,分别是虚拟地址(逻辑地址).线性地址.物理地址.在分析之前先讲一下进程执行的时候,地址的解析过程.在保护模式下,段寄存器保存的是段选择子,当进程被系统选中执行时,会把tss和ldt等 ...
- Linux0.11小结
第一部分 基础内容 1.操作系统基础 操作系统是计算机硬件系统与用户程序间重要环节,理解操作系统的原理是编写优秀代码的基础.教课书中阐述的操作系统一般由5部分组成. 一个最简单的操作系统,可以 ...
- Linux0.11启动过程
从开机加电,到执行main函数之前的过程 好吧,这里应该是有执行3个汇编的文件,但是我不太了解.囧 从main函数,到启动OK(即可以响应用户操作了) 这个步骤做了3件事情: 创建进程0,使之具备在主 ...
- Linux0.11进程切换和TSS结构
TSS 全称为task state segment,是指在操作系统进程管理的过程中,进程切换时的任务现场信息. X86体系从硬件上支持任务间的切换.为此目的,它增设了一个新段:任务状态段( ...
最新文章
- 目前研制量子计算机,18个量子比特纠缠究竟是什么水平? 量子计算机离我们还有多远?...
- 新入行程序员考虑自己是否明白以下这8件事情
- WPF:数据绑定--PropertyChangeNotification属性更改通知
- 排序方法整理Java - 冒泡排序、选择排序、插入排序、快速排序
- Python基础教程:列表解析
- [ios2]苹果iOS 5限制应用本地存储问题 【转】
- python实现随机乱序/洗牌
- vue选中点击的元素_vue中v-for循环选中点击的元素并对该元素添加样式操作
- 【算法】希尔排序 推导方法
- python读取txt文件每一行_Python3基础 file for+list 读取txt文本 并 一行一行的输出(低效率)...
- 比Magic Leap快一步,HoloLamp做到了裸眼观看全息图
- keil MDK uVision 5最新版本下载(含有注册机)
- cad2016中选择全图字体怎么操作_在学习CAD的过程中,经常会遇到的10个问题,你遇到过吗...
- 2019年微信养号攻略
- pandas 常见写法
- Derek Sivers:砍掉一切没有惊讶感的内容(译)
- React的箭头函数详解
- 今天是一位朋友的生日,送给她最美丽的祝福.
- 小米盒子打开adb调试模式
- 高端加密IC开发常见问题