操作系统实验—ucore Lab1

一、内容

通过 Lab1 中的 bootloader 可以从实模式切换的保护模式,然后再读取磁盘并加载 ELF 文件以加载 OS
操作系统,操作系统能够读入字符并显示到屏幕上,具体内容如下: 练习 1:理解通过 make 生成可执行文件的过程
练习 2:使用 qemu 执行并调试 Lab1 中的软件练习 3:分析 bootloader 进入保护模式的过程
练习 4:分析 bootloader 加载 ELF 格式的 OS 的过程练习 5:实现函数调用堆栈跟踪函数
练习 6:完善中断初始化和处理
Challenge1:增加一用户态函数,能够实现从内核态到用户态,从用户态到内核态的转化
Challenge2:需要实现用键盘实现用户模式内核模式切换

二、目的

操作系统也是一个软件,只是机器在启动时先会运行操作系统,再在操作系统下面再运行其它软件。所以我们需要了解操作系统的启动过程。机器在启动时,先运行 BIOS 用以检测启动盘,然后跳转到
bootloader 的位置运行 bootloader,随后 bootloader 会加载磁盘上的 OS 信息,开始启动 OS 操作系统。通过这次实验我们可以了解到 bootloader 的运行过程并且学会使用 gdb 调试这个过程,以及 CPU
的中断机制和函数调用过程中的堆栈关系。并且还能了解小型操作系统 ucore OS 的编译运行和启动过程, 其中里面包含了一些工具的使用。
计算机原理:
CPU 的编址与寻址: 基于分段机制的内存管理

CPU 的中断机制
外设:串口/并口/CGA,时钟,硬盘
Bootloader 软件:
编译运行 bootloader 的过程调试 bootloader 的方法
PC 启动 bootloader 的过程
ELF 执行文件的格式和加载
外设访问:读硬盘,在 CGA 上显示字符串
ucore OS 软件:
编译运行 ucore OS 的过程
ucore OS 的启动过程调试 ucore OS 的方法
函数调用关系:在汇编级了解函数调用栈的结构和处理过程中断管理:与软件相关的中断处理
外设管理:时钟

三、实验环境配置以及工具说明

实验环境:Linux 64 位用到的工具有:
1、Make,执行 makefile 中的命令,编译 OS 形成.img 文件
2、qemu,用来加载 OS 的硬件模拟器,可以模拟很多架构的硬件环境。
3、GDB,用来调试操作系统的加载过程,可以设置断点并且查看汇编代码。

四、实验步骤以及结果分析

  • 练习 1:理解通过 make 生成可执行文件的过程

1.1 ucore.img 是 如 何 一 步 一 步 生 成 的 ?
make 之后会执行 makefile 里面的指令,先对 ucore 操作系统进行编译,初始化,debug 工具,
以及一系列驱动的编译,之后生成 ucore.img 的命令如下:
在这里插入图片描述
即:
dd if=/dev/zero of=bin/ucore.img count=10000 dd if=bin/bootlock of=bin/ucore.img conv=notrunc
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
可以看到,先生成了 kernel 和 bootblock ,最后再生成.img 文件。使用 make “V=” 的指令可以将运行结果进行输出,可以看到
在这里插入图片描述
先是对 kern 中的文件进行编译生成一系列.o 文件,而 kern 文件夹下存储着就是 ucore OS 的源码。
生成 bootblock 的过程,查看 makefile 中相关内容
在这里插入图片描述
在执行过程中执行了如下指令
在这里插入图片描述
对 bootmain.c sign.c 进行了编译,最后通过 ld 进行链接生成了 bootblock
最后再生成.img 文件,我们可以了解在生成.img 文件中相关参数的含义
-if 表示输入文件

-of 表示输出文件
count 表示被赋值的块数conv=notrunc 不截短输出文件执行之后 ucore.img 生成完毕

1.2 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
我们可以进入 sign.c 中,查看关于硬盘主引导扇区的描述
在这里插入图片描述
可以看到
磁盘主引导扇区只有 512 字节
最后两个字节为 0x55AA

  • 练习 2:使用 qemu 执行并调试 lab1 中的软件

要想对整个过程进行调试,我们可以在 /tools/gdbinit 文件中更改相关信息,以便再开始调试时加载其中的指令,开始调试。
在这里插入图片描述
2.1 设定 i8086 为系统默认结构;设定与 qemu 模拟器链接的 1234 端口号;
2.2 利 用 b *addr 设置断点
在这里插入图片描述
此时断点已经设置在了 0x7c00
2.3 输入 c 程序继续进行,此时来到第二个断点 0x7c00,
在这里插入图片描述
2.4 输入 x /4i $pc 可以查看当前执行到的位置以及汇编代码
在这里插入图片描述

  • 练习 3:分析 bootloader 进入保护模式的过程

我们可以进入/boot/bootasm.S 中查看完整的过程
1.从 0x7c00 地址开始,先进入的实模式(16 位地址访问),此时会禁止中断
在这里插入图片描述
2. 然后建立重要的数据段寄存器,DS ES SS ,全部置为 0
在这里插入图片描述
3.开启的时候需要等待 8042 Input buffer 为空
在这里插入图片描述
4.然后发送 Write 8042 Output Port (P2)命令到 8042 Input buffer
在这里插入图片描述

5.然后再等待 8042 Input buffer 为空,8042 Output Port(P2)得到字节的第 2 位置 1,然后写入8042 Input buffer;
在这里插入图片描述

6.初始化 GDT 表:一个简单的 GDT 表和其描述符已经静态储存在引导区中,直接载入
在这里插入图片描述
7.进入保护模式:此时 cr0 寄存器的 PE 位置置为了 1,因此保护模式开启了
在这里插入图片描述
8.跳转之后,基址更新,真正跳转到保护状态
在这里插入图片描述

9.最后设置相关寄存器以及堆栈指针
在这里插入图片描述
call bootmain 进入保护模式完成

因此我们可以回答以下问题:
3.1 为何开启 A20 和如何开启 A20?
A20 未开启时是实模式,此时访问超过 1MB 的地址时,就会从 0 循环计数,只有开始 A20 进入保护模式时才能完整的访问 4G 内存。
打开过程如下:

  1. 等待 8042 Input buffer 为空;
  2. 发送 Write 8042 Output Port (P2)命令到 8042 Input buffer;
  3. 等待 8042 Input buffer 为空;
  4. 将 8042 Output Port(P2)得到字节的第 2 位置 1,然后写入 8042 Input buffer;

3.2 如何初始化 GDT 表?
一个简单的 GDT 表和其描述符已经静态储存在引导区中,通过 lgdt gdtdesc 载入即可

3.3 如何使能和进入保护模式?
进入保护模式:通过将 cr0 寄存器 PE 位置 1 便开启了保护模式通过长跳转更新 cs 的基地址
设置段寄存器,并建立堆栈
转到保护模式完成,进入 boot 主方法

  • 练习 4:分析 bootloader 加载 ELF 格式的 OS 的过程

4.1 bootloader 是如何读取硬盘扇区的? 流程如下:
1、等待磁盘准备好;
2、发出读取扇区的命令;
3、等待磁盘准备好;
4、把磁盘扇区数据读到指定内存

可以查看相应的代码
Bootloader 读取硬盘扇区:
在这里插入图片描述
利用 readseg 函数读取磁盘信息
在这里插入图片描述
先四舍五入到磁盘扇区的边界将字节转换到扇区
内核从扇区 1 开始
按递增的顺序开始加载磁盘内容

4.2 bootloader 是如何加载 ELF 格式的 OS? 流程如下:

  1. 读取 ELF 的头部;
  2. 判断 ELF 文件是否是合法;
  3. 将描述表的头地址存在 ph;
  4. 按照描述表将 ELF 文件中数据载入内存;
  5. 根据 ELF 头部储存的入口信息,找到内核的入口(不再返回); 具体代码如下:

读取磁盘后,先判断 ELF 是否有效
在这里插入图片描述
先加载每个程序段
在这里插入图片描述
进入 ELF 的头指针入口

之后便开始加载 ELF 里面的 OS 系统

  • 练习 5:实现函数调用堆栈跟踪函数
    1、先获取 ebp 和 eip 的值,其中. ebp 指向堆栈位置调用者的 ebp
    2、ebp+4 指向调用者调用时的 eip,ebp+8 是函数的参数
    3、bootloader 设 置 的 堆 栈 从 0x7c00 开 始 , 使 用 “call bootmain” 转入
    bootmain 函数。 call 指令压栈,所以 bootmain 中 ebp 为 0x7bf8
    4、然后通过 ebp+12,ebp+16,ebp+20,ebp+24 来输出 4 个参数的值
    5、最后更新 ebp:ebp=ebp[0],更新 eip:eip=ebp[1],直到 ebp 对应地址的值为 0
    编写的代码如下所示:
    在这里插入图片描述
  • 练习 6:完善中断初始化和处理

6.1 中断向量表中一个表项占多少字节?其中哪几位代表中断处理代码的入口?
中断描述符表(也可简称为保护模式下的中断向量表)中一个表项占 8 个字节,2-3 字节是段选择子,0-1 字节和 6-7 字节拼成位移(offset),两者联合便是中断处理程序的入口地址

在这里插入图片描述

6.2 请编程完善 kern/trap/trap.c 中对中断向量表进行初始化的函数 idt_init
先填写 IDT 表,再将表头地址告诉 LIDT,以便加载 IDT 表
在这里插入图片描述
其中 SETGATE 的宏定义如下:
在这里插入图片描述

其中有如下定义:
gate:为相应的 idt[]数组内容,处理函数的入口地址
istrap:系统段设置为 1,中断门设置为 0
sel:段选择子
off:为 vectors[]数组内容
dpl:设置特权级。这里中断都设置为内核级,即第 0 级

6.3 请编程完善 trap.c 中的中断处理函数 trap,在对时钟中断进行处理的部分填写 trap
在时钟中断中,每中断一次便将 ticks 累加 1,当加到 100 时,输出并且归零,这样便可以得到相应的功能函数,其中 print_ticks()实现的是打印功能
在这里插入图片描述
执行结果:
在这里插入图片描述

  • Challenge1:增加一用户态函数,能够实现从内核态到用户态,从用户态到内核态的转化

出于安全考虑,操作系统会将进行用户态和内核态的区分,内核态权限高,可以调用一
些系统级的操作,而用户态权限低,访问的空间和执行的操作受限。因此一些用户级的应用需要调用系统操作时,就必须要陷入操作系统提供的陷阱,只有这样才能从用户态进入内核态进行操作。
/kern/init/init.c 中
lab1_switch_to_user()是用来从内核态切换到用户态的。先需要预留一段 8 字节空间用来给之后 ss 和 esp 的入栈。
lab1_switch_to_kernel()是用来从用户态切换到内核态的。
/kern/init/init.c lab1_switch_to_user()
在这里插入图片描述
/kern/init/init.clab1_switch_to_kernel()
在这里插入图片描述

从内核态到用户态
在这里插入图片描述
从内核态到用户态,需要建立切换到用户态所需的 trapfram 结构的数据 switchk2u
将 tf_cs,tf_ds,tf_es,tf_ss 设置为用户态的代码段和数据段
设置 EFLAG 的 I/O 特权位,使得用户态可以使用 in/out 指令
设置临时栈,指向 switchk2u,这样 iret 返回时,CPU 会从 switchk2u 恢复数据,而不是现有的栈,从而完成内核态到用户态的转变 d
代码如下:
在这里插入图片描述

从用户态到内核态
在这里插入图片描述
把 tf_cs,tf_ds 等设置成内核代码和内核数据段设置 EFLAGS,让用户态不能执行 in/out 指令
设置临时栈,指向 switchu2k,当 iret 返回时,cpu 会从 switchu2k 恢复数据,而不是从现有的栈恢复数据
代码如下:
在这里插入图片描述
利用 make grade 进行验证
在这里插入图片描述
得分 40/40

  • Challenge2:需要实现用键盘实现用户模式内核模式切换

我在这采取的是在操作系统上增加一个功能,即是用户态的动作,捕捉键盘中断信号,判断接受的字符,再进行相应的转化操作。即在 while 循环中添加用户功能。
然后在进行验证判断
在这里插入图片描述

操作系统启动后输入 0,3 进行验证
在这里插入图片描述
结果正确

专业方向:软件工程-软件工程(ID:07701) 修订人:金虎 ________________________________________ 《操作系统大作业》教学大纲 第一部分 课程目的与任务 一、课程基础: 在学这门课之前,学生必须预修过高级语言、数据结构、离散数学方面的基本知识,先修操作系统课程,延时完成操作系统大作业。 二、适应对象: 计算机科学与技术-计算机应用; 软件工程-软件工程; 电子信息科学类-电子信息科学与技术;管理类-信息管理专业 三、教学目的: 为配合《操作系统》课程的教学,通过模拟操作系统原理的实现,使学生能更深刻地领会操作系统工作原理和操作系统实现方法,并提高程序设计能力, 特开设此课程设计。 四、内容提要: 本课要求模拟采用多道程序设计方法的单用户操作系统,该操作系统包括进程管理、存储管理、设备管理和文件管理四部分。 第二部分 内容及基本要求 第1章、进程控制管理实现 ●基本要求:利用简单的结构和控制方法模拟进程结构、进程状态和进程控制。 ●参考学时:8学时 ●参考资料: 用PCB表示整个进程实体,利用随机数方法或键盘控制方法模拟进程执行中产生的事件。或者利用鼠标或者键盘中断的基于图形接口方式的进程控制管理。 1、 定义PCB(可以采用静态结构或动态结构):包括理论PCB中的基本内容,如内部ID、外部ID、进程状态、队列指针。由于无法实现真正的进程创建功能,在实验中只需建立PCB,用它代表完整的进程。 2、 定义进程状态转换方式:进程的状态转换是由进程内部操作或操作系统的控制引起,由于无法实现这些功能,学生可以采用随机数方法或键盘控制方法模拟,并实现对应的控制程序。随机方法指产生1-6的随机数,分别代表创建进程(c)、结束进程(e)、进程阻塞(b)、激活进程(w)、调度进程(p)、时间片到(t)等事件;键盘模拟方法指定义6种按键代表以上6种事件。 3、 根据四种事件处理就绪队列、阻塞队列和当前执行中的进程。 每次事件处理后应形象地显示出当前系统中的执行进程是哪一个,就绪队列和阻塞队列分别包含哪些进程。 第2章、请求分页式存储管理的地址转换过程实现: ●基本要求:实现分页式存储地址转换过程,在此基础上实现请求分页的地址转换。实现请求页式地址转换中出现的缺页现象时,用到的先进先出FIFO、最近最久未使用LRU、最佳OPT置换算法。 ●参考学时:8学时 ●参考资料: 利用键盘输入本模拟系统的物理块的大小,作业的页表中的块号;完成逻辑地址转换成相应的物理地址的过程。 1、建立一张位示图,用来模拟内存的分配情况,利用随机数产生一组0和1的数对应内存的使用情况。 2、输入块(页)的大小,通过模拟位示图为本作业分配内存空间建立相应的页表(长度不定); 3、录入逻辑地址转换成相应的物理地址 4、扩充页表,变成请求式的二维页表(增加存在位等)完成地址转换。 5、输入分配给本作业的块数,模拟作业执行的逻辑地址转换成页面调度次序; 6、分别采用OPT、FIFO、LRU置换算法,利用堆栈结构完成页面置换;记录被换出的页面和新换入的页面。 第3章、设备管理实现: ●基本要求:设备管理主要包括设备的添加和删除、设备的分配和回收、同时实现设备独立性。 ●参考学时:6学时 ●参考资料: 假定模拟系统中有键盘、鼠标、打印机和显示器四个设备,三个控制器和两个通道,采用安全分配方式。 1、设备管理子系统涉及到系统设备表(SDT)、通道控制表(CHCT)、控制器控制表(COCT)和设备控制表(DCT)来体现输入输出系统的四级结构和三级控制。我们模拟这样的数据结构来完成对外围设备的管理。 (1)添加设备:增加对应的设备控制表和系统设备表中的表项,如果需要新建对应的控制器控制表。 (2)删除设备:删除对应的设备控制表和系统设备表中的表项,如果需要删除对应的控制器控制表。 2、设备的分配和回收,进程申请设备的时候,建立起通路,即获成功;否则阻塞到通道、控制器或设备上面。进程回收设备的时候,把阻塞进程唤醒。 3、设备分配必须满足设备的独立性要求。为了实现设备独立性,要求在驱动程序之上设计一层设备无关软件,其主要功能可分为: (1)执行所有设备的公有操作,主要包括:(a)独占设备的分配与回收;(b)将逻辑设备名映射为物理设备(LUT),进一步可以找到相应物理设备的驱动程序。 (2)向用户层(或文件层)软件提供统一的接口。例如,对各种设备的读操作,在应用程序中都用read; 而对各种设备的写操作,则都使用write。 第4章、文件管理系统实现: ●基本要求:利用交互式命令实现树型目录结构和文件管理,同时利用位示图表示外存的分配情况,新建文件时分配必要的空间,模拟文件分配表记录文件在外存上的存储方式。 ●参考学时:8学时 ●参考资料: 在文件中保存目录内容,创建文件或子目录可以用命令行命令:MD、CD、RD、MK(创建文件)、DEL(删除文件)和DIR。目录项包括文件或目录名称、类型(文件、目录或空目录项)、创建日期以及下一个目录项指针、下一级目录项指针。 1、创建初始文件,建立根目录的“.”和“..”目录项。 2、显示命令提示符“$”。 3、输入命令后根据命令含义完成相应文件操作: MD:在目录文件中创建子目录,同时搜索当前目录最后一个目录项,并保存指针信息; CD:根据当前目录切换到指定目录; RD:搜索所要删除的目录是否为空目录,若是则删除; MK:在当前目录中创建文件名称;(申请空间利用位示图修改FAT) DEL:搜索所要删除的文件是否存在,若是则删除;(恢复位示图修改FAT) DIR:列出当前目录的所有目录项。 4、在创建文件的时候分配空闲的磁盘空间,采用显示链接的方式,利用文件分配表(FAT)记录文件在外存上的存储情况。 5、当删除文件时,回收外存上的空间,修改位示图和文件分配表。 第5章、进程调度算法的实现: ●基本要求:实现先来先服务FCFS、短作业优先SJF以及时间片轮转调度算法。 ●参考学时:6学时 ●参考资料: 根据创建进程的系统时钟,取相对时钟作为进程的到达时间,利用随机数产生每个进程的估计运行时间。利用模拟系统中提供的算法分别计算其相应的周转时间和带权周转时间。 1、利用绝对时间和相对时钟产生一组进程的到达时刻和运行时间。 2、实现FCFS算法:根据进程的到达时间的先后次序来完成对若干进程的调度。 3、实现SJF算法:根据当前时间已经到达进程的需要运行时间选取其中时间最小的进程最先运行。 4、实现时间片轮转算法:首先要求确定时间片的大小,依据进程的到达时间依次加入队列,每次分配一个时间片大小的时间,如果没有完成参与下一次的竞争,当最后需要一个小于等于时间片的时间时本进程完成,同时退出队列。 5、计算每种算法调度后,系统的平均周转时间和平均带权周转时间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值