ImageVerifierCode 换一换
格式:DOCX , 页数:11 ,大小:448.48KB ,
资源ID:18894228      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/18894228.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(清华大学操作系统实验lab1实验报告Word文档下载推荐.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

清华大学操作系统实验lab1实验报告Word文档下载推荐.docx

1、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/

2、bootmain.o o obj/bootblock.o这句话用于生成bootblock,elf_i386表示生成elf头,0x7C00为程序的入口。这句话表示生成的bootblock的文件大小,因为大小不到512字节,所以需要给blootblock填充,填充的功能在sign.c中有所体现,最后两字节设置为了0x55,0xAAbuf510 = 0x55; buf511 = 0xAA; FILE *ofp = fopen(argv2, wb+);size = fwrite(buf, 1, 512, ofp);练习1.2 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?前面已经提到过:引导扇

3、区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA,做完这样的检查才能认为是符合规范的磁盘主引导扇区。Sign.c文件中有作检查: if (size != 512) fprintf(stderr, write %s error, size is %d.n, argv2, size); return -1; 练习2:使用qemu执行并调试lab1中的软件。练习2.1 从 CPU 加电后执行的第一条指令开始,单步跟踪 BIOS 的执行。练习2.2 在初始化位置0x7c00 设置实地址断点,测试断点正常。练习2.3 在调用qemu 时增加-d in_asm -D q.log 参数,

4、便可以将运行的汇编指令保存在q.log 中。将执行的汇编代码与bootasm.S 和 bootblock.asm 进行比较,看看二者是否一致。 实验是基于老lab1/proj1做的,练习开始时是打算用命令行一句一句执行得到结果的,后来发现直接修改makefile和gdbinit可以大大提高调试效率。 于是在makefile中增加以下代码file obj/bootblock.otarget remote :1234set architecture i8086b *0x7c00continuex /10i $pclab1-mon: $(UCOREIMG) $(V)$(TERMINAL) -e $(

5、QEMU) -S -s -d in_asm -D $(BINDIR)/q.log -monitor stdio -hda $ Data Segment movw %ax, %es # - Extra Segment movw %ax, %ss seta20.1: inb $0x64, %al # 等待8042键盘控制器不忙 testb $0x2, %al jnz seta20.1 movb $0xd1, %al # 发送写8042输出端口的指令 outb %al, $0x64seta20.2: jnz seta20.2 movb $0xdf, %al # 打开A20 outb %al, $0x

6、601、为何开启A20,以及如何开启A20?当 A20 地址线控制禁止时,则程序就像在 8086 中运行,1MB 以上的地是不可访问的。 在保护模式下 A20 地址线控制是要打开的。为了使能所有地址位的寻址能力,必须向键盘控 制器 8042 发送一个命令。键盘控制器 8042 将会将它的的某个输出引脚的输出置高电平,作 为 A20 地址线控制的输入。一旦设置成功之后,内存将不会再被绕回(memory wrapping),这 样我们就可以寻址 intel 80286 CPU 支持的 16M 内存空间,或者是寻址 intel 80386 以上级别 CPU 支持的所有 4G 内存空间了。lgdt g

7、dtdesc #把gdt表的起始位置和界限装入GDTR寄存器movl %cr0, %eax orl $CR0_PE_ON, %eax movl %eax, %cr0 #把保护模式位开启2、如何初始化GDT表?gdt: SEG_NULLASM # 空段 SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # 代码段(起始地址,大小) SEG_ASM(STA_W, 0x0, 0xffffffff) # 数据段(起始地址,大小)复习一下cr0寄存器,它的第0位为保护模式位PE:设置 PE 将让处理器工作在保护模式下。复位PE将返回到实模式工作。此外,gdtdesc指出了全局描

8、述符表在符号gdt处,如下上面四句话实现了打开保护模式位。3、如何使能进入保护模式?通过长跳转指令ljmp $PROT_MODE_CSEG, $protcseg进入了保护模式。进入保护模式之后还有一个步骤:把所有的数据段寄存器指向上面的GDT描述符表中的数据段(0x10)。练习四、分析bootloader加载ELF格式的OS的过程。static voidreadseg(uintptr_t va, uint32_t count, uint32_t offset) uintptr_t end_va = va + count; /指针移到边界 va -= offset % SECTSIZE; / 计

9、算开始读的第一个扇区号 uint32_t secno = (offset / SECTSIZE) + 1; /逐个读取扇区 for (; va 8) & outb(0x1F5, (secno 16) & outb(0x1F6, (secno 24) & 0xF) | 0xE0); outb(0x1F7, 0x20); / cmd 0x20 - read sectors / read a sector insl(0x1F0, dst, SECTSIZE / 4);0x10000。Readsect()函数的工作大致是:1. 读 I/O 地址 0x1f7,等待磁盘准备好;2. 写 I/O 地址 0x

10、1f20x1f5,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:0x%08x eip:0x%08x args:, ebp, eip); uint32_t *args = (uint32_

11、t *)ebp + 2; for (j = 0; j 4; j +) 0x%08x , argsj);n print_debuginfo(eip - 1); eip = (uint32_t *)ebp)1; ebp = (uint32_t *)ebp)0;可以获知栈底是在高地址,栈顶在低地址,压栈的次序为:参数(编程的时候默认有四个参数)、返回地址、上一层EBP、局部变量。注:read_ebp()和readeip()都是通过内联汇编实现的。 Eip-1是为了能找到上一条指令结果图:练习六、完善中断初始化和处理 (需要编程)练习6.1 中断向量表中一个表项占多少字节?其中哪几位代表中断处理代码的

12、入口?中断向量表一个表项占用8字节,其中2-3字节是段选择子,0-1字节和6-7字节拼成位移,两者联合便是中断处理程序的入口地址。2. 请编程完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init。idt_init(void) extern uintptr_t _vectors; int i; sizeof(idt) / sizeof(struct gatedesc); SETGATE(idti, 0, GD_KTEXT, _vectorsi, DPL_KERNEL); /初始化每一条IDT项 / 设置内核态到用户态的转换 SETGATE(idtT_SWITCH_T

13、OK, 0, GD_KTEXT, _vectorsT_SWITCH_TOK, DPL_USER); / 载入IDT lidt(&idt_pd);case IRQ_OFFSET + IRQ_TIMER: ticks +; if (ticks % TICK_NUM = 0) print_ticks(); /当有100次时钟中断输出一次 break;3. 请编程完善trap.c中的中断处理函数trap,在对时钟中断进行处理的部分填写trap函数中处理时钟中断的部分,使操作系统每遇到100次时钟中断后,调用print_ticks子程序,向屏幕上打印一行文字”100 ticks”。练习7、增加sysca

14、ll功能,即增加一用户态函数(可执行一特定系统调用:获得时钟计数值),当内核初始完毕后,可从内核态返回到用户态的函数,而用户态的函数又通过系统调用得到内核态的服务。 先附上两个最重要的图,分别是内核态切换到用户态、用户态切换到内核态的过程。 这部分是最花时间的,光是看代码就有很多疑问。1、为什么需要构建一个临时的trapframe来实现切换栈,切换栈说白了不就是需要修改那几个寄存器吗?2、PPT上两个切换过程中的的两个老栈顶是一个地址吗?老栈顶是什么意思?3、切换到用户态的过程中,trapframe的tf_esp为什么要指向原来的内核栈?有什么意义吗?4、切换到内核态的过程中,CPU压入的ss

15、和esp是用户栈的还是内核栈的?种种疑惑都出现在我的脑海里,加上不同的同学对这些问题有不同的理解,我也不想再去回想他们的理解了。直到看到“在执行int 120之前,系统在核心态,int不会引起切换,切换工作需在iret中完成。在执行int 121之前,系统在用户态,int引起切换,iret不需要再切换。”,感觉好像明白了一点。说一下我对上述两个过程的理解。内核到用户: 首先,我认为esp-8这个步骤不是必要的,因为从后续的过程看来,空出来的8个字节从来没有被使用过。然后开始中断,由于是在内核态,所以ss和esp暂时还不需要改变,在原来的内核栈里就可以处理。然后通过CPU压入和操作系统压入内核栈

16、的寄存器数据,构造了一个临时trapframeswitchk2u,通过pop esp跳到switchk2u,然后修改switchk2u的tf_esp,tf_ds,tf_es,tf_cs,tf_eflags,再通过一系列的pop和iret实现了对这些寄存器的修改即实现了堆栈段、代码段和数据段的切换。用户到内核:因为是int 121的关系,ss和esp在执行中断例程之前就已经切换到了内核态,此后的操作都是在内核栈,还是由压入的寄存器状态构造了一个临时的trapframeswitchk2u,把tf_cs,tf_ds,tf_es,tf_eflags改掉之后,听过一系列pop和iret跳到了正确的代码段和数据段,堆栈段就不用跳了,因为中断的时候就已经跳到内核堆栈了。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1