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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

操作系统实验ucorelab1.docx

1、操作系统实验ucorelab1一、通make生成执行文件的过程a)操作系统镜像文件ucore.img是如何一步一步生成的在编译时使用make V=,相当于设置一个标记,使得把make编译执行的过程全部展示出来。首先,调用了GCC,把一些C的源代码编译成.O的目标文件。然后,调用了ld,把这些目标文件准换成一个可执行程序,比如下面示例,转换成为了bootloader的一个执行程序bootblock.out。最后,调用了dd,把bootloader、bootblock和kernel放到虚拟的硬盘uCore.img里面。b)硬盘的主引导扇区的特征是什么在sign.c中,先申请了一个512字节的空间b

2、uf,然后将buf初始化为全0,再将主引导程序写入这个空间,最后,在buf的最后两个字节写入55AA。所以硬盘的主引导扇区的特征是主引导扇区的512个字节的最后两个字节是55AA。二、使用qemu执行并调试lab1中的软件a)从启动开始,单步跟踪BIOS的执行实验远程调用的方法,启动qemu,并让它进入-S状态。开启另外一个终端,执行gdb命令,绑定端口1234。在QEMU窗口中使用 x/10i $pc 查看最近10条指令的反汇编内容。在gdb中使用si命令执行单步,显示位置。可以看到一启动,就处于0xfffffff0的位置,第一条指令是个长跳转指令。b)在初始化位置0x7c00设置实地址断点

3、,测试断点正常输入 b *0x7c00设置断点,输入 c 执行到断点。输入x/10i $pc 查看最近10条指令的反汇编内容,可以看到qemu执行到断点0x7c00。断点工作正常。再次输入c执行,qemu继续工作。得到结论,断点工作正常。c)从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和bootblock.asm进行比较经过比较发现:gdb得到的反汇编代码与bootasm.S和bootblock.asm中的代码基本相一致。d)找一个bootloader或内核中的代码位置,设置断点并进行测试输入 b *0x7c10设置断点,输入 c 执行到断点。输入x/10i

4、$pc 查看最近10条指令的反汇编内容。输入stepi,单步执行一条机器指令。再一次输入x/10i $pc 查看最近10条指令的反汇编内容。最后,输入c,qemu继续工作。三、分析bootloader进入保护模式的过程从%cs=0 $,pc=0x7c00进入bootloader。.globl startstart: 准备:将中断标志位清0,不允许中断,设置增址,将段寄存器置0。 .code16 cli cld xorw %ax, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss 开启A20:通过将键盘控制器上的A20线置于高电位,使全部32条地址线可用

5、,进而可以访问4G的内存空间。 seta20.1: # 等待8042键盘控制器不忙 inb $0x64, %al testb $0x2, %aljnz seta20.1movb $0xd1, %al # 发送写8042输出端口的指令 outb %al, $0x64 seta20.2: # 等待8042键盘控制器不忙inb $0x64, %al testb $0x2, %aljnz seta20.2movb $0xdf, %al # 打开A20 outb %al, $0x60 加载GDTR、初始化GDT表:GDT表和其描述符已经静态储存在引导区中,载入即可。 lgdt gdtdesc进入保护模式

6、:通过将cr0寄存器PE位置1便开启了保护模式。 movl %cr0, %eax orl $CR0_PE_ON, %eax movl %eax, %cr0通过长跳转更新cs的基地址。 ljmp $PROT_MODE_CSEG, $protcseg.code32 protcseg:设置段寄存器,并建立堆栈 。 movw $PROT_MODE_DSEG, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss movl $0x0, %ebp movl $start, %esp完成进入保护模式,进入bootm

7、ain。 call bootmain四、分析bootloader加载ELF格式的OS的过程a)bootloader读取硬盘扇区readsect函数可以从设备的第secno扇区读取数据到dst位置。设置读取扇区的数目为、扇区号,读取扇区。 outb(0x1F2, 1); outb(0x1F3, secno & 0xFF); outb(0x1F4, (secno 8) & 0xFF); outb(0x1F5, (secno 16) & 0xFF); outb(0x1F6, (secno 24) & 0xF) | 0xE0); outb(0x1F7, 0x20); 读取一个扇区。 insl(0x1F

8、0, dst, SECTSIZE / 4); readseg函数包装了readsect,使得可以从设备读取任意长度的内容。 b)bootloader加载ELF格式的OS读取ELF的头部。readseg(uintptr_t)ELFHDR, SECTSIZE * 8, 0);判断是否是合法的ELF文件。if (ELFHDR-e_magic != ELF_MAGIC) goto bad;根据ELFheader和proghdr程序头,读出代码段和数据段,并且加载到相应地方。ph=(struct proghdr *)(uintptr_t)ELFHDR + ELFHDR-e_phoff); eph = p

9、h + ELFHDR-e_phnum; for (; ph p_va&0xFFFFFF, ph-p_memsz, ph-p_offset);根据ELF头部储存的入口信息,找到内核的入口。 (void (*)(void)(ELFHDR-e_entry & 0xFFFFFF)();五、实现函数调用堆栈跟踪函数因为ss:ebp指向的堆栈位置储存着跳转之前的ebp,所有,以此为线索可以得到所有使用堆栈的函数ebp。ss:ebp+4指向的是调用时的eip,ss:ebp+8等是参数。又因为bootloader设置的堆栈从0x7c00开始,使用call bootmain转入bootmain函数,所以,堆栈最

10、深一层值为ebp:0x00007bf8 eip:0x00007d68。代码分析:得到当前ebp,eip。uint32_t ebp = read_ebp(), eip = read_eip();输出ebp,eip。cprintf(ebp:0x%08x eip:0x%08x args:, ebp, eip);设置指针,输出四个参数。uint32_t *args = (uint32_t *)ebp + 2;for (j = 0; j 4; j +) cprintf(0x%08x , argsj);调用print_debuginfo函数完成查找对应函数名并打印至屏幕。print_debuginfo(e

11、ip - 1);获取上一层eip,ebp。eip = (uint32_t *)ebp)1; ebp = (uint32_t *)ebp)0;六、完善中断初始化和处理a)中断向量表中一个表项占多少字节?其中哪几位代表中断处理代码的入口?中断向量表一个表项占用8字节,其中2-3字节是段选择子,0-1字节和6-7字节拼成位移,两者联合便是中断处理程序的入口地址。b)完善对中断向量表进行初始化的函数idt_init获得IDT表的入口地址。extern uintptr_t _vectors;在中断门描述符表建立中断门描述符,其中存储了中断处理例程 的代码段GD_KTEXT和偏移量_vectorsi,特权

12、级为 DPL_KERNEL。通过查询idti就可定位到中断服务例程的起始地 址。for (i = 0; i tf_cs != USER_CS) 设置switchk2u。 switchk2u = *tf;将cs,ds,es,ss设置为用户态。 switchk2u.tf_cs = USER_CS; switchk2u.tf_ds=switchk2u.tf_es=switchk2u.tf_ss= USER_DS;设置esp值。 switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8;设置eflags值。 switchk2u.tf_

13、eflags |= FL_IOPL_MASK;设置新栈顶指向switchk2u,当返回出栈,则出栈switchk2u 中的 值。 *(uint32_t *)tf - 1) = (uint32_t)&switchk2u;b)从用户空间切换到内核空间调用lab1_switch_to_kernel函数进行从内核空间到用户空间的切换,lab1_switch_to_kernel函数内容如下:asm volatile (调用T_SWITCH_TOK号中断。 int %0 n从中断返回时,esp仍在TSS指示的堆栈中。所以要在从中断返 回后修复esp。 movl %ebp, %esp : : i(T_SWI

14、TCH_TOK);调用T_SWITCH_TOK号中断代码如下:if (tf-tf_cs != KERNEL_CS) 将cs,ds,es设置为内核态。 tf-tf_cs = KERNEL_CS; tf-tf_ds = tf-tf_es = KERNEL_DS;设置eflags值。 tf-tf_eflags &= FL_IOPL_MASK;设置switchu2k值。switchu2k=(struct trapframe *)(tf-tf_esp-(sizeof(struct trapframe) - 8);用tf值覆盖switchu2k值。 memmove(switchu2k, tf, sizeo

15、f(struct trapframe) - 8);设置新栈顶指向switchk2u,当返回出栈,则出栈switchk2u 中的值。 *(uint32_t *)tf - 1) = (uint32_t)switchu2k;八、问题a)配置环境我首先主要遇到的问题是安装一个代码阅读的工具,因为代码量比较大而且函数间相互调用很多。最后安装了understand,首先下载软件压缩包,然后解压到安装目录,再添加路径,最后输入证书号。还有一个是在运行make qemu时报错,解决办法是:建立符号链接文件”ln -s /usr/local/bin/qenu-system-i386 /usr/local/bin

16、/qemu”。b)在练习2时,设置断点在0x7c20时,没有在断点处停止后来才了解到设置断点时,断点处的信息会被修改,有时由于设置断点刚好设置在一条指令中间,这样信息修改后,原指令一部分未被覆盖,与断点的机器码可能恰好组成其他的指令,所以没有停止。所以,设置断点时应该注意要设置在一条指令完成之后,而不要设置在一条指令中间。c)在练习4,无法理解readseg(uintptr_t)ELFHDR, SECTSIZE * 8, 0)在询问后知道,这句代码并不是获取bootloader,而是获取读取ELF文件的头部,所以大小不是512字节,应该是512*8字节,也就是一页4k。d)在练习5,无法理解堆

17、栈最深一层值为ebp:0x00007bf8查阅后知道,在编译器会在每个函数体之前插入pushl %ebpmovl %esp,%ebp所以堆栈最深一层ebp为0x 7c00-0008=7bf8。e)在扩展练习中,无法理解sub $0x8, %esp 和movl %ebp, %esp讲解后知道,sub $0x8, %esp 是因为,从中断返回时,会多pop两位,并用这两位的值更新ss、sp,所以要先把栈压两位。movl %ebp, %esp是因为,从中断返回时,esp仍在TSS指示的堆栈中,所以要在从中断返回后修复esp。f)在扩展练习中,如何只使用一个栈空间实现从内核空间到用户空间的切换修改代码

18、如下 ,但是报错,不知道问题在哪里。 case T_SWITCH_TOU: if (tf-tf_cs != USER_CS) tf-tf_cs = USER_CS; tf-tf_ds = tf-tf_es = tf-tf_ss = USER_DS; tf-tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; tf-tf_eflags |= FL_IOPL_MASK; *(uint32_t *)tf - 1) = (uint32_t)&tf; 和同学讨论后,发现是最后一句代码有误。应该为 *(uint32_t *)tf - 1) = (uint32_t)tf;tf本来就是一个指针,不需要再加地址符。

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

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