Part 2

学习理论知识

反汇编

把机器语言转换为汇编语言代码

扇区

对于PC来说,软盘,硬盘都可以被划分为一个个大小为512字节的区域,叫做扇区。一个扇区是一次磁盘操作的最小粒度。每一次读取或者写入操作都必须是一个或多个扇区。如果一个磁盘是可以被用来启动操作系统的,就把这个磁盘的第一个扇区叫做启动扇区。当BIOS找到一个可以启动的软盘或硬盘后,它就会把这512字节的启动扇区加载到内存地址0x7c00~0x7dff这个区域内。

BIOS 启动过程总结
  • 计算机加电后,一般不直接执行操作系统,而是执行系统初始化软件完成基本IO初始化和引导加载功能。简单地说,系统初始化软件就是在操作系统内核运行之前运行的一段小软件。通过这段小软件,我们可以初始化硬件设备、建立系统的内存空间映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。最终引导加载程序把操作系统内核映像加载到RAM中,并将系统控制权传递给它。

  • 对于绝大多数计算机系统而言,操作系统和应用软件是存放在磁盘(硬盘/软盘)、光盘、EPROM、ROM、Flash等可在掉电后继续保存数据的存储介质上。计算机启动后CPU一开始会到一个特定的地址开始执行指令,这个特定的地址存放了系统初始化软件,负责完成计算机基本的IO初始化,这是系统加电后运行的第一段软件代码。对于Intel 80386的体系结构而言,PC机中的系统初始化软件由BIOS (Basic Input Output System,即基本输入/输出系统,其本质是一个固化在主板Flash/CMOS上的软件)和位于软盘/硬盘引导扇区中的OS Boot Loader(在ucore中的bootasm.S和bootmain.c)一起组成。BIOS实际上是被固化在计算机ROM(只读存储器)芯片上的一个特殊的软件,为上层软件提供最底层的、最直接的硬件控制与支持。更形象地说,BIOS就是PC计算机硬件与上层软件程序之间的一个"桥梁",负责访问和控制硬件。

  • 以Intel 80386为例,计算机加电后,CPU从物理地址0xFFFFFFF0(由初始化的CS:EIP确定,此时CS和IP的值分别是0xF000和0xFFF0))开始执行。在0xFFFFFFF0这里只是存放了一条跳转指令,通过跳转指令跳到BIOS例行程序起始点。BIOS做完计算机硬件自检和初始化后,会选择一个启动设备(例如软盘、硬盘、光盘等),并且读取该设备的第一扇区(即主引导扇区或启动扇区)到内存一个特定的地址0x7c00处,然后CPU控制权会转移到那个地址继续执行。至此BIOS的初始化工作做完了,进一步的工作交给了bootloader。

  • 计算机加电后,首先处于 实模式 ,经过boot loader转换后切换到32-bit 保护模式

Boot loader启动过程总结

BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader。bootloader完成的工作包括:

  • 切换到保护模式,启用分段机制
  • 读磁盘中ELF执行文件格式的操作系统到内存
  • 显示字符串信息
  • 把控制权交给操作系统

对应实现文件../boot/boot.S 和 ../boot/main.c

A20 gate
  1. 8088/8086只有20位地址线,按理它的寻址空间是2^20,应该是1024KB,但PC机的寻址结构是segment:offset,所以segment:offset所能表达的寻址空间最大应为0ffff0h + 0ffffh = 10ffefh(大约1088kB)
  • 当你用segment:offset的方式企图寻址100000h这个地址时,由于没有实际的第21位地址线,你实际寻址的内存是00000h的位置,如果你企图寻址100001h这个地址时,你实际得到的内容是地址00001h上的内容

    • 这个事对实际使用几乎没有任何影响,但是后来就不行了,出现了80286,地址线达到了24位,使segment:offset寻址100000h--10ffefh这将近64K的存储器成为可能,为了保持向下兼容,于是出现了A20 Gate
  1. 扩展内存:1M以上的内存寻址空间

    • 这里面绝大部分内存区域只能在保护模式下才能寻址到,
    • 但有一部分既可以在保护模式下,也可以在实模式下寻址,这就是我们前面提到过的地址100000h--10ffefh之间的这块内存,为了表明其特殊性,我们把这块有趣的内存区叫做“高端内存”
    • (如果当初IBM把上位内存区的东西放在低端,就没有这么多麻烦了)
  2. ROM和RAM的地址重叠

    • 实际的内存条上地址都是连续的,采用技术手段把这段地址空间空出来给ROM 用,比浪费这384K内存的成本还要高 所以采用ROM和RAM的地址重叠
    • 实际上,往往ROM并不能完全覆盖整个384K区域,这样就会有一些地址没有被ROM占用,那么这部分地址上的RAM仍然是可以使用的。
    • ROM Shadowing:
      • RAM和ROM的性能是有很大差异的,RAM的存取速度要远远大于ROM,而且RAM可以32位存取,ROM通常只能16位
      • 当机器加电后,先让ROM有效,RAM无效,然后读出ROM内容,再让ROM无效,RAM有效,把读出的ROM内容放到相同地址的RAM中,并把相应位置的RAM设定为只读,这样就把ROM搬到了RAM中,地址完全一样,只是性能比使用ROM要高些,这块RAM就好像ROM的Shadow一样。
  3. A20 gate:

    • 出现80286以后,为了保持和8086的兼容,需要使用第21根地址总线在设计上在第21条地址线(也就是A20)上做了一个开关,当这个开关打开时,这条地址线和其它地址线一样可以使用,当这个开关关闭时,第21条地址线(A20)恒为0

    • A20 gate在什么时候需要打开

      • 实模式下要访问高端内存区,这个开关必须打开

      • 保护模式下,由于使用32位地址线,如果A20恒等于0,那么系统只能访问奇数兆的内存,即只能访问0--1M、2-3M、4-5M......,这显然是不行的,所以在保护模式下,这个开关也必须打开

    • PC如何实现A20 gate:

      • 用8042芯片(控制键盘的单独的单片机),但与键盘毫无关系

参考资料:https://blog.csdn.net/jxth152913/article/details/52512663

读boot/boot.S 和 boot/boot.c源码

- boot/boot.S
  • 该文件的目的:

    1. start CPU, switch to 32-bit protected mode(启动CPU 并且最终转到32-bit 保护模式)
    2. BIOS loads code from first sector of the hard disk into memory at physical addr 07xc00
    3. executing in real mode (%cs=0, %ip=7c00)
  • 步骤:

    1. 初始化重要的segment registers,全部初始化为0
    2. 16位指令下,屏蔽中断,初始化段寄存器
    3. 开启A20 gate,停止取模运算,将高位的空间也可访问
    4. 利用bootstrap GDT转换到protected mode
    5. 跳转到32-bit模式下的下一个指令
    6. 然后在32-bit 保护模式下,设置保护模式的寄存器
    7. 设置stack pointer 然后调用main.c执行main.c里面的bootmain函数
  • 关于开启A20 gate的代码部分解析:

11  # Enable A20:
12 # For backwards compatibility with the earliest PCs, physical
13 # address line 20 is tied low, so that addresses higher than
14 # 1MB wrap around to zero by default. This code undoes this.
15 seta20.1:
16 inb $0x64,%al # Wait for not busy
17 testb $0x2,%al
18 jnz seta20.1 19 movb $0xd1,%al # 0xd1 -> port 0x64
20 outb %al,$0x64 21 seta20.2:
22 inb $0x64,%al # Wait for not busy
23 testb $0x2,%al
24 jnz seta20.2 25 movb $0xdf,%al # 0xdf -> port 0x60
26 outb %al,$0x60

​ 这部分指令就是在准备把CPU的工作模式从实模式转换为保护模式。我们可以看到其中的指令包括inb,outb这样的IO端口命令。所以这些指令都是在对外部设备进行操作。根据下面的链接:

   http://bochs.sourceforge.net/techspec/PORTS.LST

  我们可以查看到,0x64端口属于键盘控制器804x,名称是控制器读取状态寄存器。下面是它各个位的含义。

  

  所以16~18号指令是在不断的检测bit1。bit1的值代表输入缓冲区是否满了,也就是说CPU传送给控制器的数据,控制器是否已经取走了,如果CPU想向控制器传送新的数据的话,必须先保证这一位为0。所以这三条指令会一直等待这一位变为0,才能继续向后运行。

  当0x64端口准备好读入数据后,现在就可以写入数据了,所以19~20这两条指令是把0xd1这条数据写入到0x64端口中。当向0x64端口写入数据时,则代表向键盘控制器804x发送指令。这个指令将会被送给0x60端口。

  

  通过图中可见,D1指令代表下一次写入0x60端口的数据将被写入给804x控制器的输出端口。可以理解为下一个写入0x60端口的数据是一个控制指令。

  然后21~24号指令又开始再次等待,等待刚刚写入的指令D1,是否已经被读取了。

  如果指令被读取了,25~26号指令会向控制器输入新的指令,0xdf。通过查询我们看到0xDF指令的含义如下

  

  这个指令的含义可以从图中看到,使能A20线,代表可以进入保护模式了。

boot.S & main.c 代码分析链接:

https://www.cnblogs.com/fatsheep9146/p/5115086.html

- boot/mian.c
  • boot.S & main.c存在磁盘第一个扇区

  • 第二个扇区开始保存kernel

  • 内核需为ELF格式

  • Boot up steps:

    1. CPU启动后,加载BIOS进入内存并执行它
    2. BIOS初始化设备、一系列中断准备、读取第一个扇区的boot device到内存并跳到该处
    3. 从boot.S开始控制,它建立保护模式+1个stack,以便C代码可以跑,然后调用bootmain()函数
    4. bootmain()函数读取内核并跳到内核
  • segment 和 sector的关系:一个segment包含多个sector

  • readsect(void *dst, uint32_t offset)

  • readseg(uchar *pa, uint count, uint offset)

    它的功能从注释上来理解是,把距离内核起始地址offset个偏移量存储单元作为起始,将它和它之后的count字节的数据读出送入以pa为起始地址的内存物理地址处。

mit-6.828 Lab01:Booting a PC Part2 理论知识的更多相关文章

  1. 《MIT 6.828 Lab1: Booting a PC》实验报告

    <MIT 6.828 Lab1: Booting a PC>实验报告 本实验的网站链接见:Lab 1: Booting a PC. 实验内容 熟悉x86汇编语言.QEMU x86仿真器.P ...

  2. MIT 6.828 JOS学习笔记2. Lab 1 Part 1.2: PC bootstrap

    Lab 1 Part 1: PC bootstrap 我们继续~ PC机的物理地址空间 这一节我们将深入的探究到底PC是如何启动的.首先我们看一下通常一个PC的物理地址空间是如何布局的:        ...

  3. MIT 6.828 JOS学习笔记1. Lab 1 Part 1: PC Bootstrap

    Lab 1: Booting a PC Part 1: PC Bootstrap 介绍这一部分知识的目的就是让你能够更加熟悉x86汇编语言,以及PC启动的整个过程,而且也会首次学习使用QEMU软件来仿 ...

  4. MIT 6.828 JOS学习笔记0. 写在前面的话

    0. 简介 操作系统是计算机科学中十分重要的一门基础学科,是一名计算机专业毕业生必须要具备的基础知识.但是在学习这门课时,如果仅仅把目光停留在课本上一些关于操作系统概念上的叙述,并不能对操作系统有着深 ...

  5. 《MIT 6.828 Homework 1: boot xv6》解题报告

    本作业的网站链接:MIT 6.828 Homework 1: boot xv6 问题 Exercise: What is on the stack? While stopped at the abov ...

  6. 《MIT 6.828 Lab 1 Exercise 3》实验报告

    本实验的网站链接:mit 6.828 lab1 Exercise 3. 题目 Exercise 3. Take a look at the lab tools guide, especially th ...

  7. 《MIT 6.828 Lab 1 Exercise 2》实验报告

    本实验链接:mit 6.828 lab1 Exercise2. 题目 Exercise 2. Use GDB's si (Step Instruction) command to trace into ...

  8. MIT 6.828 课程介绍

    MIT 6.828 课程介绍 本文是对MIT 6.828操作系统课程介绍的简单摘录,详细介绍见6.828: Learning by doing以及朱佳顺的推荐一门课:6.828.学习资源均可以在课程主 ...

  9. 《MIT 6.828 Homework 2: Shell》解题报告

    Homework 2的网站链接:MIT 6.828 Homework 2: shell 题目 下载sh.c文件,在文件中添加相应代码,以支持以下关于shell的功能: 实现简单shell命令,比如ca ...

  10. 《MIT 6.828 Lab 1 Exercise 12》实验报告

    本实验的网站链接:MIT 6.828 Lab 1 Exercise 12. 题目 Exercise 12. Modify your stack backtrace function to displa ...

随机推荐

  1. eclipse中导入项目后中文成乱码解决办法

    转自:http://blog.163.com/lang_zi_ming/blog/static/1140161762010412112650774/ 编程时在往eclipse中导入项目后 项目中的中文 ...

  2. linux中proc文件系统 -- ldd3读书笔记

    1./proc 文件系统概述 /proc 文件系统是由软件创建,被内核用来向外界报告信息的一个文件系统./proc 下面的每一个文件都和一个内核函数相关联,当文件的被读取时,与之对应的内核函数用于产生 ...

  3. 2016 11 9遇到问题 http请求的各种方式

    遇到问题:对接网易七鱼 调用他们接口是出现问题 1.对方要求  除上传文件外,其他所有接口请求Content-Type类型为:application/json;charset=utf-8:请求内容需要 ...

  4. AngularJS中数据双向绑定(two-way data-binding)

    1.切换工作目录 git checkout step-4 #切换分支,切换到第4步 npm start #启动项目 2.代码 app/index.html Search: <input ng-m ...

  5. Atcoder R84 D Small Multiple

    题意:给定一个正整数K,求K的倍数中,各位上的数字之和最小是多少? 思路非常巧妙,对于一个数,我们有定义两种改变方式: 1.加1,则数字之和+1(9的情况另行考虑) 2.乘10,数字之和不变 对于末位 ...

  6. webpack使用教程

    webpack使用教程 接触webpack也有挺长一段时间了,公司的项目也是一直用着webpack在打包处理,但前几天在教新人的情况下,遇到了一个问题,那就是:尽管网上的webpack教程满天飞,但是 ...

  7. Oracle数据重复,只取一条

    --方法一 select * from tb_supply where rowid=any(select max(rowid) from tb_supply group by phone_id) -- ...

  8. 手机配置代理报错invalid host header

    手机配置代理后浏手机弹出页面报错invalid host header,因为我是用fiddler配置的,所以这时候就要看下自己配置完之后,是否重启,重启之后就没问题了. fiddle配置参考:http ...

  9. gh-ost安装

    下载 : https://github.com/github/gh-ost/releases/tag/v1.0.28 先安装Go语言: sudo yum install golang 将gh-ost文 ...

  10. Mui --- 弹出菜单

    mui框架内置了弹出菜单插件,弹出菜单显示内容不限,但必须包裹在一个含.mui-popover类的div中,如下即为一个弹出菜单内容: <div id="popover" c ...