lab1
前言
这是中山大学数据科学与计算机学院2019年操作系统实验中关于Ucore的项目以及实验报告,实验要求与Ucore手则有少量出入。
所有源代码已经上传至github。
github个人主页: https://starashzero.github.io
项目地址: https://github.com/StarashZero/Ucore-homework
【实验题目】系统软件启动过程
【实验目的】
操作系统是一个软件,也需要通过某种机制加载并运行它。在这里我们将通过另外一个更加简单的软件-bootloader 来完成这些工作。为此,我们需要完成一个能够切换到x86 的保护模式并显示字符的bootloader,为启动操作系统ucore 做准备。lab1 提供了一个非常小的bootloader 和ucoreOS,整个bootloader 执行代码小于512 个字节,这样才能放到硬盘的主引导扇区中。通过分析和实现这个bootloader 和ucore OS,读者可以了解到:
● 基于分段机制的存储管理
● 设备管理的基本概念
● PC 启动bootloader 的过程
● bootloader 的文件组成
● 编译运行 bootloader 的过程
● 调试 bootloader 的方法
● ucore OS 的启动过程
● 在汇编级了解栈的结构和处理过程
● 中断处理机制
● 通过串口/并口/CGA 输出字符的方法
【实验方案】
包括:硬件或虚拟机配置方法、软件工具与作用、方案的思想、相关原理、程序流程、算法和数据结构、程序关键模块,结合代码与程序中的位置位置进行解释,组员工作分工。
虚拟机使用Ubuntu,主要的代码编辑与查看工具VSCode,结合Ucore启动过程指导与网上的资料完成实验。
练习 1:理解通过make 生成执行文件的过程。(要求在报告中写出对下述问题的回答)
在此练习中,大家需要通过静态分析代码来了解:
- 操作系统镜像文件 ucore.img 是如何一步一步生成的?(需要比较详细地解释Makefile 中每一条相关命令和命令参数的含义,以及说明命令导致的结果)
首先找到创建ucore.img的makefile代码如下
# create ucore.img
UCOREIMG := $(call totarget,ucore.img)
$(UCOREIMG): $(kernel) $(bootblock)
$(V)dd if=/dev/zero of=$@ count=10000
$(V)dd if=$(bootblock) of=$@ conv=notrunc
$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc
$(call create_target,ucore.img)
可以看到要生成ucore.img首先要生成kernel和bootblock
生成kernel代码如下
# create kernel target
kernel = $(call totarget,kernel)
$(kernel): tools/kernel.ld
$(kernel): $(KOBJS)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)
@$(OBJDUMP) -S $@ > $(call asmfile,kernel)
@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)
$(call create_target,kernel)
运行makefile,在其中找到kernel的实际命令为
关键参数
-m 模拟指定的连接器
-nostdlib 不使用标准库
-T 指定命令文件
-o 指定输出文件的名称
可以发现生成kernel所需要的文件有:tools/kernel.ld obj/kern/init/init.o obj/kern/libs/readline.o obj/kern/libs/stdio.o obj/kern/debug/kdebug.o obj/kern/debug/kmonitor.o obj/kern/debug/panic.o obj/kern/driver/clock.o obj/kern/driver/console.o obj/kern/driver/intr.o obj/kern/driver/picirq.o obj/kern/trap/trap.o obj/kern/trap/trapentry.o obj/kern/trap/vectors.o obj/kern/mm/pmm.o obj/libs/printfmt.o obj/libs/string.o
生成这些文件的makefile为下面的批处理代码
# kernel
KINCLUDE += kern/debug/ \
kern/driver/ \
kern/trap/ \
kern/mm/
KSRCDIR += kern/init \
kern/libs \
kern/debug \
kern/driver \
kern/trap \
kern/mm
KCFLAGS += $(addprefix -I,$(KINCLUDE))
$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))
其实际代码为(以init.o为例)
关键参数
-fno-bultin 除非用_builtin_前缀,否则不进行builtin函数的优化
-ggdb 此选项将尽可能的生成gdb的可以使用的调试信息
-m32 生成适用于32位环境的代码
-gstabs 此选项以stabs格式声称调试信息,但是不包括gdb调试信息
-nostdinc 使编译器不在系统缺省的头文件目录里面找头文件
-fno-stack-protector不生成用于检测缓冲区溢出的代码
-I<dir> 添加搜索头文件的路径
kernel生成完成
生成blootblock的makefile代码如下
# create bootblock
bootfiles = $(call listf_cc,boot)
$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
bootblock = $(call totarget,bootblock)
$(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)
$(call create_target,bootblock)
其生成代码为
关键参数:
-N设置代码段和数据段均可读写
可以看到生成bootblock需要bootasm.o,bootmain.o,以及sign
bootasm.o和bootmain.o由以下makefile代码生成
bootfiles = $(call listf_cc,boot)
$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))
实际代码为
sign的makefile代码为
# create 'sign' tools
$(call add_files_host,tools/sign.c,sign,sign)
$(call create_target_host,sign,sign)
生成代码为
2. 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
char buf[512];
memset(buf, 0, sizeof(buf));
FILE *ifp = fopen(argv[1], "rb");
int size = fread(buf, 1, st.st_size, ifp);
if (size != st.st_size) {
fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size);
return -1;
}
fclose(ifp);
buf[510] = 0x55;
buf[511] = 0xAA;
一个磁盘主引导扇区512字节,且第510个字节为0X55,第511个字节为0XAA