Intel 80386

ucore目前支持的硬件环境是基于Intel 80386以上的计算机系统。

Intel 80386是80x86系列中的第一种32位微处理器。80386的内部和外部数据总线都是32位,地址总线也是32位,可寻址高达4GB内存。

工作方式包括实模式、保护模式以及虚拟86模式。

Bootloader

我们知道计算机启动是从BIOS开始,再由BIOS决定从哪个设备启动以及启动顺序,比如先从DVD启动再从硬盘启动等。计算机启动后,BIOS根据配置找到启动设备,并读取这个设备的第0个扇区,把这个扇区的内容加载到0x7c00,之后让CPU从0x7c00开始执行,这时BIOS已经交出了计算机的控制权,由被加载的扇区程序接管计算机。
这第一个扇区的程序就叫Boot,它一般做一些准备工作,把操作系统内核加载进内存,并把控制权交给内核。由于Boot只能有一个扇区大小,即512字节,它所能做的工作很有限,因此它有可能不直接加载内核,而是加载一个叫Loader的程序,再由Loader加载内核。因为Loader不是BIOS直接加载的,所以它可以突破512字节的程序大小限制(在实模式下理论上可以达到1M)。如果Boot没有加载Loader而直接加载内核,我们可以把它叫做Bootloader。
Bootloader加载内核就要读取文件,在实模式下可以用BIOS的INT 13h中断。内核文件放在哪里,怎么查找读取,这里牵涉到文件系统,Bootloader要从硬盘(软盘)的文件系统中查找内核文件,因此Bootloader需要解析文件系统的能力。GRUB是一个专业的Bootloader,它对这些提供了很好的支持。
对于一个Toy操作系统来说,可以简单处理,把内核文件放到Bootloader之后,即从软盘的第1个扇区开始,这样我们可以不需要支持文件系统,直接读取扇区数据加载到内存即可。

MBR与磁盘分区

  在目前x86的系统架构中,系统硬盘位于第0号磁道:0到511KB的区块为MBR(硬盘中的每一个磁道容量为512KB),开机管理程序使用这块区域来储存第一阶段开机引导程序(stage1)。接着位于1到62号磁道作为第1.5阶段的开机引导程序(stage1.5),从第63号磁道开始才是操作系统的分区。

  主引导记录(MBR,Master Boot Record)是位于磁盘最前边的一段引导(Loader)代码。它负责磁盘操作系统(DOS)对磁盘进行读写时分区合法性的判别、分区引导信息的定位,它由磁盘操作系统(DOS)在对硬盘进行初始化时产生。

  MBR的内容分为三部分:第一部分是0到445KB,是计算机的基础导引程序,也称为第一阶段的导引程序;接着446KB到509KB为磁盘分区表,由四个分区表项构成(每个16个字节)。负责说明磁盘上的分区情况。内容包括分区标记、分区的起始位置、分区的容量以及分区的类型。最后一部分为结束标志只占2KB,其值为AA55,存储时低位在前,高位在后。

从百度百科借了张图:

MBR中紧跟在主引导程序后的主分区表这64字节(01BE~01FD)中包含了许多磁盘分区描述信息,尤其是01BE~01CD这16字节,包含了分区引导标志bootid、分区起始源头beghead、分区起始扇区relsect、分区起始柱面begcy1、操作系统类型systid、分区结尾磁头endhead、分区结尾扇区begsect、分区结尾柱面begcy1、分区扇区起始位置relsect、分区扇区总数numsect。

其中分区引导标志bootid表示当前分区是否可以引导,若为0x0,则表示该分区为非活动区;若为0x80,则为可开机启动区。若有多个开机启动区,则由用户开机时的选择而定(如GRUB的菜单)。

分区扇区起始位置relsect表示分区中第一个扇区相对于磁盘起始点的偏移位置。

实模式到保护模式

我们知道Intel x86系列CPU有实模式和保护模式,实模式从8086开始就有,保护模式从80386开始引入。为了兼容,Intel x86系列CPU都支持实模式。现代操作系统都是运行在保护模式下(Intel x86系列CPU)。计算机启动时,默认的工作模式是实模式,为了让内核能运行在保护模式下,Bootloader需要从实模式切换到保护模式,切换步骤如下:
  1. 准备好GDT(Global Descriptor Table)
  2. 关中断
  3. 加载GDT到GDTR寄存器
  4. 开启A20,让CPU寻址大于1M
  5. 开启CPU的保护模式,即把cr0寄存器第一个bit置1
  6. 跳转到保护模式代码
GDT是Intel CPU保护模式运行的核心数据结构,所有保护模式操作的数据都从GDT表开始查找,这里有GDT的详细介绍。
GDT中的每一个表项由8字节表示,如下图:
其中Access Byte和Flags如下图:
这里是详细说明。
GDTR是一个6字节的寄存器,有4字节表示GDT表的基地址,2字节表示GDT表的大小,即最大65536(实际值是65535,16位最大值是65535),每个表项8字节,那么GDT表最多可以有8192项。
实模式的寻址总线是20bits,为了让寻址超过1M,需要开启A20,可以通过以下指令开启:
    in al, 0x92
    or al, 2
    out 0x92, al
把上述步骤完成之后,我们就进入保护模式了。在保护模式下我们要使用GDT通过GDT Selector完成,它是GDT表项相对于起始地址的偏移,因此它的值一般是0x0 0x8 0x10 0x18等。

A20

1981年8月,IBM公司最初推出的个人计算机IBM PC使用的CPU是Inter 8088.在该微机中地址线只有20根。在当时内存RAM只有几百KB或不到1MB时,20根地址线已经足够用来寻址这些 内存。其所能寻址的最高地址是0xffff,

也就是0x10ffef。对于超出0x100000(1MB)的寻址地址将默认地环绕到0xffef。当IBM公司与1985年引入AT机时,使用的是Inter 80286 CPU,具有24根地址线,最高可寻址16MB,并且有一个与8088那样实现地址寻址的环绕。

但是当时已经有一些程序是利用这种环绕机制进行工作的。为了实现完全的兼容性,IBM公司发明了使用一个开关来开启或禁止0x100000地址比特位。由于当时的8042键盘控制器上恰好有空闲的端口引脚(输出端口P2,引脚P21),

于是便使用了该引脚来作为与门控制这个地址比特位。该信号即被称为A20。如果它为零,则比特20及以上地址都被清除。从而实现了兼容性。

当A20地址线控制禁止时,程序就像运行在8086上,1MB以上的地址是不可访问的,只能访问奇数MB的不连续的地址。为了使能所有地址位的寻址能力,必须向键盘控制器8082发送一个命令,键盘控制器8042会将A20线置于高电位,使全部32条地址线可用,实现访问4GB内存。

GDT

GDT全称是Global Descriptor Table,中文名称叫“全局描述符表”,想要在“保护模式”下对内存进行寻址就先要有 GDT。GDT 表里的每一项叫做“段描述符”,用来记录每个内存分段的一些属性信息,每个“段描述符”占 8 字节。

在保护模式下,我们通过设置GDT将内存空间被分割为了一个又一个的段(这些段是可以重叠的),这样我们就能实现不同的程序访问不同的内存空间。这和实模式下的寻址方式是不同的, 在实模式下我们只能使用address = segment << 4 | offset的方式进行寻址(虽然也是segment + offset的,但在实模式下我们并不会真正的进行分段)。在这种情况下,任何程序都能访问整个1MB的空间。而在保护模式下,通过分段的方式,程序并不能访问整个内存空间

ELF文件

Bootloader程序是原始可执行文件,如果程序由汇编写成,汇编编译器编译生成的文件就是原始可执行文件,也可以使用C语言编写,编译成可执行文件之后通过objcopy转换成原始可执行文件,这篇文章介绍了用C语言写Bootloader。
那么内核文件是什么格式的呢?跟Bootloader一样的当然可以。内核一般使用C语言编写,每次编译链接完成之后调用objcopy是可以的。我们也可以支持通用的可执行文件格式,ELF(Executable and Linkable Format)即是一种通用的格式,它的维基百科
ELF文件有两种视图(View),链接视图和执行视图,如下图:

链接视图通过Section Header Table描述,执行视图通过Program Header Table描述。Section Header Table描述了所有Section的信息,包括所在的文件偏移和大小等;Program Header Table描述了所有Segment的信息,即Text Segment, Data Segment和BSS Segment,每个Segment中包含了一个或多个Section。

对于加载可执行文件,我们只需关注执行视图,即解析ELF文件,遍历Program Header Table中的每一项,把每个Program Header描述的Segment加载到对应的虚拟地址即可,然后从ELF header中取出Entry的地址,跳转过去就开始执行了。对于ELF格式的内核文件来说,这个工作就需要由Bootloader完成。Bootloader支持ELF内核文件加载之后,用C语言编写的内核编译完成之后就不需要objcopy了。

中断

中断的具体内容(点击)

ucore实验Lab1知识点总结的更多相关文章

  1. 清华大学OS操作系统实验lab1练习知识点汇总

    lab1知识点汇总 还是有很多问题,但是我觉得我需要在查看更多资料后回来再理解,学这个也学了一周了,看了大量的资料...还是它们自己的80386手册和lab的指导手册觉得最准确,现在我就把这部分知识做 ...

  2. 关于ucore实验一的资料查找

    任务:阅读实验一makefile 搞清楚ucore.img是如何构建的 $@  $<  $^  这三个变量分别是什么意思 https://blog.csdn.net/YEYUANGEN/arti ...

  3. lab_0 清华大学ucore实验环境配置详细步骤!(小白入)

    实验步骤 1.下载项目 从github上 的https://github.com/kiukotsu/ucore下载 ucore lab实验: git clone https://github.com/ ...

  4. 《ucore lab1 exercise1》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:理解通过make生成执行文件的过程 列出本实验各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关 ...

  5. 《ucore lab1 exercise5》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:实现函数调用堆栈跟踪函数 我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_s ...

  6. 《ucore lab1》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 练习1:理解通过make生成执行文件的过程 详见<ucore lab1 exercise1>实验报告 练习2:使用qemu执行并调试 ...

  7. 《ucore lab1 exercise3》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:分析bootloader进入保护模式的过程 BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader.请分 ...

  8. 《ucore lab1 exercise2》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:使用qemu执行并调试lab1中的软件 为了熟悉使用qemu和gdb进行的调试工作,我们进行如下的小练习: 从CPU加电后执行的第一条指令 ...

  9. 《ucore lab1 exercise4》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:分析bootloader加载ELF格式的OS的过程 通过阅读bootmain.c,了解bootloader如何加载ELF文件.通过分析源代 ...

随机推荐

  1. putty连接centos慢

    用的vmware下的centos minimal镜像,开发时,用putty连接很慢,一分多钟, 解决方案: 禁用GSSAPI认证有两个方式:客户端和服务端 直接配置你ssh客户端的文件/etc/ssh ...

  2. mask-rcnn代码解读(七):display(self)函数的解析

    如和将class中定义的变量打印或读取出来,受maskrcnn的config.py的启示,我将对该函数进行解释. 我将介绍该函数前,需要对一些名词进行解释,如下: ①Ipython:ipython是一 ...

  3. Map-HashMap-遍历

    第一种遍历方法 : 先获取Map中的所有key值,然后根据key,依次从Map中去数据 (针对只取 Key 或者 Value 的情况) Map<String, String> hashMa ...

  4. C++优先队列例子

    #pragma GCC optimize(3) #include <bits/stdc++.h> #define N 105 using namespace std; struct Nod ...

  5. BUUCTF Hack World

    有返回 ,基于布尔得盲注这里用到异或注入(个人喜欢这样用)1^0 返回 Hello, glzjin wants a girlfriend.1^1 返回 Error Occured When Fetch ...

  6. 章节十四、9-Actions类鼠标悬停、滚动条、拖拽页面上的元素

    一.鼠标悬停 1.在web网站中,有一些页面元素只需要我们将鼠标指针放在上面就会出现被隐藏的下拉框或者其它元素,在自动化的过程中我们使用Actions类对鼠标进行悬停操作. 2.案例演示 packag ...

  7. [b0018] python 归纳 (四)_运算符重载

    # -*- coding: UTF-8 -*- """ 测试运算符重载 加法 总结: python 运算符表达式其实都是调用 类中方法 __xxx__ + <--- ...

  8. Python 安装cx_Oracle模块

    1.Python安装cx_Oracle模块需要安装Oracle,并在环境变量中添加Oracle的路径. 2.没有安装Oracle的需要下载一个oci.dll的文件,并把文件的路径添加到path中. 如 ...

  9. 构建Apache Web服务器

    Apache 是世界使用排名第一的 Web 服务器软件.它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的 Web 服务器端软件之一.Apache工作模式有多种,其 ...

  10. FusionSphere产品功能

    华为Fusion产品 FusionSphere解决方案的三种场景 服务器虚拟化 NFVI:运营商基于openstack kvm协议的解决方案 云数据中心 FusionSphere服务器虚拟化解决方案 ...