清华大学操作系统lab1_实验报告.docx_第1页
清华大学操作系统lab1_实验报告.docx_第2页
清华大学操作系统lab1_实验报告.docx_第3页
清华大学操作系统lab1_实验报告.docx_第4页
清华大学操作系统lab1_实验报告.docx_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

实验1:系统软件启动过程练习1:(1) 操作系统镜像文件 ucore.img 是如何一步一步生成的?在命令行中输入“make v=”1、首先把c的源代码进行编译成为.o文件,也就是目标文件(红色方框内)2、 ld命令将这些目标文件转变成可执行文件,比如此处的bootblock.out(绿色方框内)3、dd命令把bootloder放到ucore.img count的虚拟硬盘之中4、还生成了两个软件,一个是bootloader,另一个是kernel。(2)一个被系统认为是符合规范的硬盘主引导扇区的特征: 在/lab1/tools/sign.c中我们可以了解到 规范的硬盘引导扇区的大小为512字节,硬盘结束标志位55aa练习2:(1) 从 cpu 加电后执行的第一条指令开始,单步跟踪 bios 的执行改写makefile文件lab1-mon: $(ucoreimg)$(v)$(terminal) -e $(qemu) -s -s -d in_asm -d $(bindir)/q.log -monitor stdio -hda $ ds: data segment movw %ax, %es # - es: extra segment movw %ax, %fs # - fs movw %ax, %gs # - gs movw %ax, %ss # - ss: stack segment # 设置堆栈 movl $0x0, %ebpmovl $start, %esp # 栈顶为0x7c00# 进入bootmain,不再返回 call bootmainspin:jmp spin练习4:分析bootloader加载elf格式的os的过程 读一个扇区的流程可参看bootmain.c 中的 readsect 函数实现。大致如下:1. 读 i/o 地址 0x1f7,等待磁盘准备好;2. 写 i/o 地址 0x1f20x1f5,0x1f7,发出读取第 offseet 个扇区处的磁盘数据的命令;3. 读 i/o 地址 0x1f7,等待磁盘准备好;4. 连续读 i/o 地址 0x1f0,把磁盘扇区数据读到指定内存。static voidreadsect(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); / cmd 0x20 - read sectors / wait for disk to be ready waitdisk(); / read a sector insl(0x1f0, dst, sectsize / 4);该函数封装在readseg函数中,该函数完成读取任意的长度。notice: uint32_t secno = (offset / sectsize) + 1; # 0号扇区已被引导占用。最后在bootmain函数中完成加载elf格式os的操作:1: 读取elf的头部2: 判断elf文件是否是合法3: 将描述表的头地址存在ph4: 按照描述表将elf文件中数据载入内存5: 根据elf头部储存的入口信息,找到内核的入口(不再返回)notice:可能会出现内存长度文件长度的现象 多读入部分包含bss节,需要清0练习5:实现函数调用堆栈跟踪函数print_stackframe(void) 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_t *)ebp + 2; /(uint32_t)calling arguments 0.4 = the contents in address (unit32_t)ebp +2 0.4 for (j = 0; j 4; j +) cprintf(0x%08x , argsj); cprintf(n); print_debuginfo(eip - 1); /*call print_debuginfo(eip-1) to print the c calling function name and line number, etc.*/ eip = (uint32_t *)ebp)1; ebp = (uint32_t *)ebp)0;/popup a calling stackframe notice:ss:ebp指向的堆栈位置储存着caller的ebp,以此为线索可以得到所有使用堆栈的函数ebp。ss:ebp+4指向caller调用时的eip,ss:ebp+8等是(可能的)参数。练习6:(1)中断向量表中一个表项占多少字节?其中哪几位代表中断处理代码的入口?中断向量表一个表项占用8字节,其中2-3字节是段选择子,0-1字节和6-7字节拼成位移,入口地址=段选择子+段内偏移量。(2) 完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init可以在/lab1/kern/mm/mmu.h中可以找到setgate函数,查找其具体操作。idt_init(void) extern uintptr_t _vectors; int i; for (i = 0; i tf_cs != user_cs) switchk2u = *tf; switchk2u.tf_cs = user_cs; switchk2u.tf_ds = switchk2u.tf_es = switchk2u.tf_ss = user_ds; switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8;/在执行int120前系统在核心态,int不会引起栈的切换 switchk2u.tf_eflags |= fl_iopl_mask; *(uint32_t *)tf - 1) = (uint32_t)&switchk2u; break;最后iret时返回5个值。(2) 用户态切换到内核态:lab1_switch_to_kernel(void) asm volatile ( int %0 n movl %ebp, %esp n : : i(t_switch_tok);case t_switch_tok: if (tf-tf_cs != kernel_cs) tf-tf_cs = kernel_cs; tf-tf_ds = tf-tf_es = kernel_ds; tf-tf_eflags &= fl_iopl_mask;/定位临时栈的栈顶 switchu2k = (struct trapframe *)(tf-tf_esp - (sizeof(struct trapframe) - 8); /复制 memmove(switchu2k, tf, sizeof(struct trapframe) - 8);/在执行int120前系统在核心态,int会引起栈的切换,iret不会引起/

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论