OS_Lab 1 Booting a PC

Last updated on 8 months ago

image-20220206112414457

step5 是课程导论,介绍该课程的安排以及Unix的使用

这次作业是 介绍汇编和一些工具的使用

image-20220206113644102

现在开始:

Software Setup

先把源码 该章节的源码 clone下来

1
git clone https://pdos.csail.mit.edu/6.828/2018/jos.git

image-20220206113212423

这两部分是 clone源码和该怎么用 git交作业的 不必细说

image-20220206113411035

Part 1: PC Bootstrap

1. Getting Started with x86 assembly

​ 这里申明了 该os是采用 AT&T 风格 的汇编(我接触比较多的是 Intel 风格) 这部分是 让我们熟悉汇编语言,接下来的课程 打好基础,(我会另起一章专门写汇编)

2. Simulating the x86

进入目录 make

image-20220206145945011

可能会有这个报错! 这是 一个整数是 64位除以 一个数位32位的时候 ,官方说安装 gcc-multilib
但没什么用,我直接把这个函数参数成32位了…先这样再说吧(这个是打印数字的 函数)

image-20220206145349817

运行 qemu (关于的qemu的安装,网上有很多)

image-20220206150545992

The PC’s Physical Address Space

下图是 内存的布局(4gb),早期的内存只有 1Mb,为了兼容以前的所以还是保留下来,这1Mb 接下来我们会使用到!

image-20220206205505422

Part 2: The Boot Loader

part2 是引导程序 BootLoader 的介绍, 这个是什么呢?

​ 电脑启动是时候 会有个
​ 一句话来表达就是 系统运作之前 所运行的程序,当我们按了开机键,首先是 运行这个程序,现在的大多数电脑 这个程序都 写死在主板里(GRUB?)。

  • 这个程序有什么用?
  1. 硬件自检,如显卡 ,声卡那些…
  2. 这个并不是真正的操作系统,所以这个程序的作用是 找到 OS,并把这个OS程序加载到内存中 (OS 也是一个程序!),随后转让控制权。
  • 这个 BootLoader 程序 cpu怎么找到的呢?
    开机的时候,就开是扫描 硬盘,硬盘被划分为512字节的区域,称为扇区,一个硬盘有很多扇区,扫一次 就一个扇区,如果找到了(如何判定? 如果这个扇区的最后两个字节内容是0x55和0xAA 则就是要找的 ) 将这个 512 字节扇区加载到内存地址为 0x7c00(为什么是这个,这个是有来源的 ,大家可以找下),加载完成后 ,执行 cpu 就跳到 0x7c00 处开始执行程序,

Exercise 3

看 os启动的流程 ,gdb调试 ,启动主要有两个文件 boot/main.c 和 boot.s

1
2
3
4
5
Exercise 3.   Take a look at the [lab tools guide](https://pdos.csail.mit.edu/6.828/2018/labguide.html), especially the section on GDB commands. Even if you're familiar with GDB, this includes some esoteric GDB commands that are useful for OS work.

Set a breakpoint at address 0x7c00, which is where the boot sector will be loaded. Continue execution until that breakpoint. Trace through the code in `boot/boot.S`, using the source code and the disassembly file `obj/boot/boot.asm` to keep track of where you are. Also use the `x/i` command in GDB to disassemble sequences of instructions in the boot loader, and compare the original boot loader source code with both the disassembly in `obj/boot/boot.asm` and GDB.

Trace into `bootmain()` in `boot/main.c`, and then into `readsect()`. Identify the exact assembly instructions that correspond to each of the statements in `readsect()`. Trace through the rest of `readsect()` and back out into `bootmain()`, and identify the begin and end of the `for` loop that reads the remaining sectors of the kernel from the disk. Find out what code will run when the loop is finished, set a breakpoint there, and continue to that breakpoint. Then step through the remainder of the boot loader.

开始gdb调试

一个窗口运行 make qemu-gdb (开启了个端口)
再开一个窗口运行 make gdb (运行行了一个gdb脚本,远程调试)

image-20220207124829335

现在我们开始 打断点 教材里有说说到是 从 0x7c00 开始的,断点设到 0x7c00 ,b -》 break

image-20220207125156235

c 一直执行知道遇到断点
si 意为 执行下一步汇编
x/N ADDR 为看这个地址的汇编指令 N为查看几条指令
info register : 查看 寄存器的值

image-20220207125543005

按照教材意思 比对 boot反汇编的代码和 gdb调试的代码

boot返汇编的代码在这,比对了下 objdump 反汇编的出的风格还是 Intel的, 和gdb 调试也差多少 ,从 0x7c00开始一步一看吧

image-20220207131053481

boot.o 反汇编的代码

image-20220207131245606

当调试到 这一步时 地址为 0x7c2d时候 ,提示现在处于 i386状态(32位下)
image-20220207171214490

在反汇编的代码中 也可以看出 7c2d 后有 伪指令 .code32 意为切换到32位模式
image-20220207171406343

关于 elf 得新开一个章节 来描述

这里加载从磁盘里加载内核 ,怎么加载呢?结合elf 头 的信息,看要读多少
image-20220207204857874

这里是 把内核 读到 内存里并执行
首先有个问题是怎么读? (这里涉及到elf 的内容,elf 详细内容不在该章节细说)
elf 头 我们已经从 磁盘中读到内存了,目前只是elf 的头部读到内存了,但是 elf 所包含的程序段 没有读到内存里,所以呢,

image-20220207222201306

Exercise 4.

​ 检查下你的对指针的运用,就是指针运用基础,注意下 不同类型的指针的步长

Exercise 5,6

debug 查看从 boot 加载 kernel 的过程,这些可以对照boot.o 反汇编的文件和 kernel的反汇编文件逐步调试对照,就可以清楚的知道了

Part 3: The Kernel

这部分开始讲 虚拟内存,开始之前再重新 把前面的内容捋一遍!

qemu启动,执行 从boot 代码段执行,
从内存地址 0x7c00 处开始执行代码
关闭中断,开启 A20线, 开起gdt
调用 bootmain 函数
加载 内核文件 到内存里
首先是 加载 elf头
根据elf 头提供的信息,把elf文件中的 程序段加载到对应的内存中
(不是很详细,后续再补充 )

​ 跳到 elf 的入口函数 entry
image-20220208111501673


Part3 讲的是虚拟内存 和 物理内存的映射,在这把那些细节 描述的很清楚,给了个结论,让我们去验证下,

Exercise 7

验证 物理地址转换虚拟地址

执行 movl %eax, %cr0 后就开启了 分页 ,可以看到地址不同

image-20220208112758744

image-20220208113037678

执行 movl %eax, %cr0 前 0xf0100000 内存都是空的
image-20220208113823730

执行后 0x 100000 映射到了 0xf0100000
image-20220208113835668

Formatted Printing to the Console

Read through kern/printf.c, lib/printfmt.c, and kern/console.c, and make sure you understand their relationship. It will become clear in later labs why printfmt.c is located in the separate lib directory.
看这些 源码,print 实现也大同小异,相对于 《JamesM’s kernel development tutorials 》 ,我觉的后者 print实现 比较容易理解!可以去参考下

Exercise 8
print 有个 %o 没实现,就是 数字按照 8进制打印出来 ,下图仿照 %x 输出 写了个,就是换个参数..

image-20220208133154527

os 最开始的运行时,有打印一个
image-20220208133403998

没修过前是 输出

image-20220208133514813

添加 %o 输出后 15254 是 8进制,转成 10 进制 6828

image-20220208133607963

很多细节,先放下,后续再补…

The Stack

Exercise 9

看 栈的初始地址 在哪里

image-20220208153047528

从以上 代码可以看到 初始化了esp 和 edp,这函数调用的深入下也可以写很多东西,先挖个坑吧….
初始化后 看下两个寄存器的 值
image-20220208165110291

可以得出 栈的地址是冲 0xf0110000 开始的

esp 指向了栈的指针 , bootstacktop 的定义我们可以看下 (合理 运用 ide ,我是用 vscode全局查的)

image-20220208165822004

可以的出 栈的大小为 8 * 4096 字节 (SPACE申请一片内存空间)…..

带更新,,,