清华大学操作系统实验lab1实验报告
更新时间:2024-04-11 04:40:01 阅读量: 综合文库 文档下载
- 清华大学操作系统教材推荐度:
- 相关推荐
练习1、理解通过make生成执行文件的过程。
[练习1.1] 操作系统镜像文件 ucore.img 是如何一步一步生成的? 在proj1执行命令make V=可以得到make指令执行的过程
make V= + cc boot/bootasm.S gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootasm.S -o obj/boot/bootasm.o + cc boot/bootmain.c gcc -Iboot/ -fno-builtin -Wall -ggdb -m32 -nostdinc -fno-stack-protector -Ilibs/ -Os -nostdinc -c boot/bootmain.c -o obj/boot/bootmain.o + cc tools/sign.c gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign + ld bin/bootblock ld -m elf_i386 -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o -o obj/bootblock.o 'obj/bootblock.out' size: 440 bytes build 512 bytes boot sector: 'bin/bootblock' success! dd if=/dev/zero of=bin/ucore.img count=10000 记录了10000+0 的读入 记录了10000+0 的写出 5120000字节(5.1 MB)已复制,0.0227439 秒,225 MB/秒 dd if=bin/bootblock of=bin/ucore.img conv=notrunc 记录了1+0 的读入 记录了1+0 的写出 512字节(512 B)已复制,0.000214966 秒,2.4 MB/秒
从这几条指令中可以看出需要生成ucore.img首先需要生成bootblock,而生成bootblock需要先生成bootmain.o和bootasm.o还有sign,这三个文件又分别由bootmain.c、bootasm.S、sigh.c来生成。
ld -m elf_i386 -N -e start -Ttext 0x7C00 obj/boot/bootasm.o obj/boot/bootmain.o – o obj/bootblock.o
这句话用于生成bootblock,elf_i386表示生成elf头,0x7C00为程序的入
口。
'obj/bootblock.out' size: 440 bytes
这句话表示生成的bootblock的文件大小,因为大小不到512字节,所以需要给blootblock填充,填充的功能在sign.c中有所体现,最后两字节设置为了0x55,0xAA
buf[510] = 0x55;
buf[511] = 0xAA;
FILE *ofp = fopen(argv[2], \); size = fwrite(buf, 1, 512, ofp);
[练习1.2] 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
前面已经提到过:引导扇区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA,做完这样的检查才能认为是符合规范的磁盘主引导扇区。
Sign.c文件中有作检查:
if (size != 512) { }
fprintf(stderr, \, argv[2], size); return -1;
练习2:使用qemu执行并调试lab1中的软件。
[练习2.1] 从 CPU 加电后执行的第一条指令开始,单步跟踪 BIOS 的执行。 [练习2.2] 在初始化位置0x7c00 设置实地址断点,测试断点正常。
[练习2.3] 在调用qemu 时增加-d in_asm -D q.log 参数,便可以将运行的汇编指令保存在q.log 中。将执行的汇编代码与bootasm.S 和 bootblock.asm 进行比较,看看二者是否一致。
实验是基于老lab1/proj1做的,练习开始时是打算用命令行一句一句执行得到结果的,后来发现直接修改makefile和gdbinit可以大大提高调试效率。
于是在makefile中增加以下代码
lab1-mon: $(UCOREIMG) $(V)$(TERMINAL) -e \-serial null\ $(V)sleep 2 $(V)$(TERMINAL) -e \ tools/gdbinit\ -S –s是使得qemu在执行第一条指令之前停下来,在调用qemu时增加-d
in_asm -D q.log参数,便可以将运行的汇编指令保存在q.log中。然后sleep
两秒应该是给qemu充分的时间准备等待连接。接下来使用GDB调试工具,-tui提供了代码与命令行分屏查看的界面,tools/gdbinit中存放的是gdb调试file obj/bootblock.o target remote :1234 set architecture i8086 b *0x7c00 continue x /10i $pc 指令如下。
先是加载调试文件,然后连接qemu,设置8086的实模式,设置断点0x7c00,也就是bootloader的第一条指令,然后运行到断点。再显示接下来的10条指令。
运行结果图如下
很明显,断点位置的代码和boot.asm文件中的代码完全一致,说明断点设置成功。打开q.log文件看,看到了很奇葩的结果。能够看到cli,cld之类熟悉的指令,但是他们的地址以及出现的顺序都不是想象的那样(从0x0x00007c00k开始,第一条指令为cld)。
之后听大神解释,在q.log中进入BIOS之后的跳转地址与实际应跳转地址不相符,汇编代码也 与bootasm.S 和 bootblock.asm不相同。
可以通过make debug之后在qemu的控制台中输入x /10i $pc看到BIOS
执行bootloader部分的代码。
进过对比,这些代码 与bootasm.S与bootblock.asm中的代码完全一致。
练习3 分析bootloader 进入保护模式的过程。
在开启A20之前,BIOS还做了很多事:关中断、清除方向标志,给各个数据段清零。
cli # Set up the important data segment registers (DS, ES, SS). xorw %ax, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss # Segment number zero # -> Data Segment # -> Extra Segment # Disable interrupts # String operations cld increment
seta20.1: seta20.2: movb $0xdf, %al outb %al, $0x60 # 打开A20 inb $0x64, %al testb $0x2, %al jnz seta20.2 # 等待8042键盘控制器不忙 movb $0xd1, %al outb %al, $0x64 # 发送写8042输出端口的指令 inb $0x64, %al testb $0x2, %al jnz seta20.1 # 等待8042键盘控制器不忙 1、为何开启A20,以及如何开启A20?
当 A20 地址线控制禁止时,则程序就像在 8086 中运行,1MB 以上的地是不可访问的。 在保护模式下 A20 地址线控制是要打开的。为了使能所有地址位的寻址能力,必须向键盘控 制器 8042 发送一个命令。键盘控制器 8042 将会将它的的某个输出引脚的输出置高电平,作 为 A20 地址线控制的输入。一旦设置成功之后,内存将不会再被绕回(memory wrapping),这 样我们就可以寻址 intel 80286 CPU 支持的 16M 内存空间,或者是寻址 intel 80386 以上级别 CPU 支持的所有 4G 内存空间了。 2、如何初始化GDT表?
lgdt gdtdesc #把gdt表的起始位置和界限装入GDTR寄存器 movl %cr0, êx orl $CR0_PE_ON, êx movl êx, %cr0 #把保护模式位开启 复习一下cr0寄存器,它的第0位为保护模式位PE:设置 PE 将让处理器工
gdt: SEG_NULLASM # 空段 # 代码段(起始地址,大小) # 数据段(起始地址,大小) SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) SEG_ASM(STA_W, 0x0, 0xffffffff) 作在保护模式下。复位PE将返回到实模式工作。此外,gdtdesc指出了全局描述符表在符号gdt处,如下
上面四句话实现了打开保护模式位。 3、如何使能进入保护模式? 通过长跳转指令
ljmp $PROT_MODE_CSEG, $protcseg 进入了保护模式。
进入保护模式之后还有一个步骤:把所有的数据段寄存器指向上面的GDT描述符表中的数据段(0x10)。
练习四、分析bootloader加载ELF格式的OS的过程。
在proj2中,增加主要增加了对磁盘简单的读取函数readsect() readseg()),
以及对ELF头的解析(ELF头结构在ELF.h文件中)。
static void readseg(uintptr_t va, uint32_t count, uint32_t offset) { } //实现了从kernel复制8个扇区(包含ELF头,共4KB)到0x10000 uintptr_t end_va = va + count; //指针移到边界 va -= offset % SECTSIZE; // 计算开始读的第一个扇区号 uint32_t secno = (offset / SECTSIZE) + 1; //逐个读取扇区 for (; va < end_va; va += SECTSIZE, secno ++) { } readsect((void *)va, secno); 疑问:为什么要把ELF头读到0X10000?从哪读?
以下为一些硬件端口上实现读取一个扇区到内存0x10000。
/* readsect - read a single sector at @secno into @dst */ static void readsect(void *dst, uint32_t secno) { } // wait for disk to be ready waitdisk(); outb(0x1F2, 1); // count = 1 outb(0x1F3, secno & 0xFF); outb(0x1F4, (secno >> 8) & 0xFF); outb(0x1F5, (secno >> 16) & 0xFF); outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0); outb(0x1F7, 0x20); waitdisk(); // read a sector insl(0x1F0, dst, SECTSIZE / 4); // cmd 0x20 - read sectors // wait for disk to be ready Readsect()函数的工作大致是:
1. 读 I/O 地址 0x1f7,等待磁盘准备好;
2. 写 I/O 地址 0x1f2~0x1f5,0x1f7,发出读取第 offseet 个扇区处的磁盘数据的命令;
3. 读 I/O 地址 0x1f7,等待磁盘准备好;
4. 连续读 I/O 地址 0x1f0,把磁盘扇区数据读到指定内存。
练习五、实现函数调用堆栈跟踪函数(需要编程)
可以获知栈底是在高地址,栈顶在低地址,压栈的次序为:参数(编程的时
uint32_t ebp = read_ebp(), eip = read_eip(); int i, j; for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) { cprintf(\, ebp, eip); uint32_t *args = (uint32_t *)ebp + 2; for (j = 0; j < 4; j ++) { cprintf(\, args[j]); } cprintf(\); print_debuginfo(eip - 1); eip = ((uint32_t *)ebp)[1]; ebp = ((uint32_t *)ebp)[0]; 候默认有四个参数)、返回地址、上一层EBP、局部变量。 注:read_ebp()和readeip()都是通过内联汇编实现的。
Eip-1是为了能找到上一条指令
结果图:
练习六、完善中断初始化和处理 (需要编程)
[练习6.1] 中断向量表中一个表项占多少字节?其中哪几位代表中断处理代码的入口?
中断向量表一个表项占用8字节,其中2-3字节是段选择子,0-1字节和6-7字节拼成位移,两者联合便是中断处理程序的入口地址。
idt_init(void) { extern uintptr_t __vectors[]; int i; for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) { SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL); }//初始化每一条IDT项 // 设置内核态到用户态的转换 SETGATE(idt[T_SWITCH_TOK], 0, GD_KTEXT, __vectors[T_SWITCH_TOK], DPL_USER); } // 载入IDT lidt(&idt_pd); 2. 请编程完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init。
3. 请编程完善trap.c中的中断处理函数trap,在对时钟中断进行处理的部分填写trap函数中处理时钟中断的部分,使操作系统每遇到100次时钟中断后,调用print_ticks子程序,向屏幕上打印一行文字”100 ticks”。
case IRQ_OFFSET + IRQ_TIMER: ticks ++; if (ticks % TICK_NUM == 0) { print_ticks(); }//当有100次时钟中断输出一次 break;
练习7、增加syscall功能,即增加一用户态函数(可执行一特定系统调用:获得时钟计数值),当内核初始完毕后,可从内核态返回到用户态的函数,而用户态的函数又通过系统调用得到内核态的服务。
先附上两个最重要的图,分别是内核态切换到用户态、用户态切换到内核
态的过程。
这部分是最花时间的,光是看代码就有很多疑问。
为什么需要构建一个临时的trapframe来实现切换栈,切换栈说白了不就是需要修改那几个寄存器吗? 2、
PPT上两个切换过程中的的两个老栈顶是一个地址吗?老栈顶是什么意思? 1、
3、 切换到用户态的过程中,trapframe的tf_esp为什么要指向原来的内核栈?有什么意义吗?
4、 切换到内核态的过程中,CPU压入的ss和esp是用户栈的还是内核栈的?
种种疑惑都出现在我的脑海里,加上不同的同学对这些问题有不同的理解,我也不想再去回想他们的理解了。直到看到“在执行int 120之前,系统在核心态,int不会引起切换,切换工作需在iret中完成。在执行int 121之前,系统在用户态,int引起切换,iret不需要再切换。”,感觉好像明白了一点。
说一下我对上述两个过程的理解。
? 内核到用户: 首先,我认为esp-8这个步骤不是必要的,因为从后续的过
程看来,空出来的8个字节从来没有被使用过。然后开始中断,由于是在内核态,所以ss和esp暂时还不需要改变,在原来的内核栈里就可以处理。然后通过CPU压入和操作系统压入内核栈的寄存器数据,构造了一个临时trapframe——switchk2u,通过pop esp跳到switchk2u,然后修改switchk2u的tf_esp,tf_ds,tf_es,tf_cs,tf_eflags,再通过一系列的pop和iret实现了对这些寄存器的修改——即实现了堆栈段、代码段和数据段的切换。
? 用户到内核:因为是int 121的关系,ss和esp在执行中断例程之前就已经切
换到了内核态,此后的操作都是在内核栈,还是由压入的寄存器状态构造了一个临时的trapframe——switchk2u,把tf_cs,tf_ds,tf_es,tf_eflags改掉之后,听过一系列pop和iret跳到了正确的代码段和数据段,堆栈段就不用跳了,因为中断的时候就已经跳到内核堆栈了。
正在阅读:
清华大学操作系统实验lab1实验报告04-11
小学英语四年级上册教学计划(赵秀丽)05-26
辛伐他汀在短暂性脑缺血发作治疗和二级预防中的应用效果观察_刘忠华05-13
北师大版五年级下册数学期中易错题测试试卷(附答案)05-29
广东省汕头市金山中学2014-2015学年高一上学期期末数学试卷09-10
形容花香的成语02-10
浅谈小学音乐欣赏课的教学策略04-19
成功的味道作文500字06-28
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 实验
- 清华大学
- 操作系统
- 报告
- lab1
- 上海市发展和改革委员会委托投资咨询评估管理办法
- 沙尔湖煤矿生产安全事故综合应急预案
- 倒立摆实验书 - 图文
- 2019年中国硅胶行业市场需求与投资规划分析报告目录
- 工程地质工程施工钻工题库
- UNIS桌面云项目方案建议书-南京紫光云信息 - 图文
- 高鸿业西方经济学微观部分第6版课后习题详解第3章消费者选择
- 北师大版数学七年级下册计算题大全(70)
- 重庆大足石刻英语导游词
- 海外投资保险实务1
- JAVA期末复习资料
- 2018年原创经典RBA 6.0 责任商业联盟行为准则解读之全套文件合集
- 初一语文12月份月考试题
- 康桥柴郭安置房一号院项目策划书 - 图文
- 开题报告 杨康Microsoft Word 文档
- 昌江县水资源概况
- 四年级数学 谢修永 用计算器探索规律
- 微博舆论传播论文开题报告 - 图文
- 多传感器数据采集与传输电路设计毕业论文 - 图文
- 甲级单位编制废旧扬声器项目可行性报告(立项可研+贷款+用地+201