Exercise 1

Exercise 1. Familiarize yourself with the assembly language materials available on the 6.828 reference page. You don’t have to read them now, but you’ll almost certainly want to refer to some of this material when reading and writing x86 assembly.

We do recommend reading the section “The Syntax” in Brennan’s Guide to Inline Assembly. It gives a good (and quite brief) description of the AT&T assembly syntax we’ll be using with the GNU assembler in JOS.

练习1的目的是为了熟悉汇编语言,但是不必马上就去学习编写,可以在阅读代码和编写代码的时候去查阅。但是强烈要求看一下Brennan’s的关于"The Syntax"这部分的内容

Exercise 2

Exercise 2.Use GDB’s si (Step Instruction) command to trace into the ROM BIOS for a fewmore instructions, and try to guess what it might be doing. You might want to look at PhilStorrs I/O Ports Description, as well as other materials on the 6.828 reference materials page.No need to figure out all the details - just the general idea of what the BIOS is doing first

练习2的目的是为了使用GDB调试程序,可以尝试猜测接下来会干什么。你可能想要阅读Phil Storrs PC Hardware book或者6.828参考材料中的其他的材料。没有必要理解所有的细节,仅仅只需要了解BIOS最开始做什么

Exercise 3

Exercise 3. Take a look at the lab tools guide, especially the section on GDB commands. Even if you’re familiar with GDB, this includes some esoteric GDB commands that are useful for OS work.

Set a breakpoint at address 0x7c00, which is where the boot sector will be loaded. Continue execution until that breakpoint. Trace through the code in boot/boot.S, using the source code and the disassembly file obj/boot/boot.asm to keep track of where you are. Also use the x/i command in GDB to disassemble sequences of instructions in the boot loader, and compare the original boot loader source code with both the disassembly in obj/boot/boot.asm and GDB.

Trace into bootmain() in boot/main.c, and then into readsect(). Identify the exact assembly instructions that correspond to each of the statements in readsect(). Trace through the rest of readsect() and back out into bootmain(), and identify the begin and end of the for loop that reads the remaining sectors of the kernel from the disk. Find out what code will run when the loop is finished, set a breakpoint there, and continue to that breakpoint. Then step through the remainder of the boot loader.

练习3的目的主要是为了熟悉使用GDB,同时观察引导扇区和内核的具体运作方式。要回答四个问题

  1. At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bitmode?
ljmp    $PROT_MODE_CSEG, $protcseg

从这句开始,执行完就从16位实模式切换到32位保护模式了

  1. What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it justloaded?
((void (*)(void)) (ELFHDR->e_entry))();

bootloader最后一行代码是这一条,整个bootmain函数的作用就是从硬盘读取内核,然后跳到entry入口,执行内核。

镜像文件是按照elf格式存在硬盘上的,ELFHDR是指向0x10000,整个内核程序块是从0x10000(物理地址)开始运行的。entry的虚拟地址,在之前打印过,是0xf010000c,转化成物理地址为0x10000c。所以内核加载的第一条指令是movw $0x1234,0x472

  1. Where is the first instruction of the kernel?
movw   $0x1234,0x472
  1. How does the boot loader decide how many sectors it must read in order to fetch the entire kernel from disk?Where does it find this information?

elf格式文件有写,具体结构可以参考ELF文件结构,读取操作看main.creadsect函数。最终概括成以下这句话

一个扇区大小为512字节。读一个扇区的流程大致为通过outb指令访问I/O地址:0x1f2~-0x1f7来发出读扇区命令,通过in指令了解硬盘是否空闲且就绪,如果空闲且就绪,则通过inb指令读取硬盘扇区数据都内存中。

ELF文件具体格式如下

I/O地址功能
0x1f0读数据,当0x1f7不为忙状态时,可以读。
0x1f2要读写的扇区数,每次读写前,需要指出要读写几个扇区。
0x1f3如果是LBA模式,就是LBA参数的0-7位
0x1f4如果是LBA模式,就是LBA参数的8-15位
0x1f5如果是LBA模式,就是LBA参数的16-23位
0x1f6第0~3位:如果是LBA模式就是24-27位第4位:为0主盘;为1从盘
第6位:为1=LBA模式;0= CHS模式第7位和第5位必须为1
0x1f7状态和命令寄存器。操作时先给命令,再读取内容;如果不是忙状态就从0x1f0端口读数据

Exercise 4

Exercise 4. Read about programming with pointers in C. The best reference for the C language is The C Programming Language by Brian Kernighan and Dennis Ritchie (known as ‘K&R’). We recommend that students purchase this book (here is an Amazon Link) or find one of MIT’s 7 copies.

Read 5.1 (Pointers and Addresses) through 5.5 (Character Pointers and Functions) in K&R. Then download the code for pointers.c, run it, and make sure you understand where all of the printed values come from. In particular, make sure you understand where the pointer addresses in printed lines 1 and 6 come from, how all the values in printed lines 2 through 4 get there, and why the values printed in line 5 are seemingly corrupted.

There are other references on pointers in C (e.g., A tutorial by Ted Jensen that cites K&R heavily), though not as strongly recommended.

Warning: Unless you are already thoroughly versed in C, do not skip or even skim this reading exercise. If you do not really understand pointers in C, you will suffer untold pain and misery in subsequent labs, and then eventually come to understand them the hard way. Trust us; you don’t want to find out what “the hard way” is.

练习4的目的是为了熟悉C语言代码规则,主要是看K&R的前5章内容,尤其是第五章关于指针部分的内容。可以自行查看

Exercise 5

Exercise 5. Trace through the first few instructions of the boot loader again and identify the first instruction that would “break” or otherwise do the wrong thing if you were to get the boot loader’s link address wrong. Then change the link address in boot/Makefrag to something wrong, run make clean, recompile the lab with make, and trace into the boot loader again to see what happens. Don’t forget to change the link address back and make clean again afterward!

练习5的目的是为了验证boot/Makefrag设置链接地址的正确性。需要make clean, 然后修改0x7c00的数值,尝试实验就可以。其实可以发现并不能启动

Exercise 6

Exercise 6.We can examine memory using GDB’s x command. The GDB manual has fulldetails, but for now, it is enough to know that the command x/Nx ADDR prints N words ofmemory at ADDR. (Note that both 'x’s in the command are lowercase.) Warning: The size of aword is not a universal standard. In GNU assembly, a word is two bytes (the ‘w’ in xorw, whichstands for word, means 2 bytes).

Reset the machine (exit QEMU/GDB and start them again). Examine the 8 words of memoryat 0x00100000 at the point the BIOS enters the boot loader, and then again at the point the bootloader enters the kernel. Why are they different? What is there at the second breakpoint? (You do not really need to use QEMU to answer this question. Just think.)

练习6主要是使用GDB去查看启动时,加载过程,可以在0x7c000x0010000c地址处加断点,使用x/Nx ADDR打印加载的地址,主要是看0x00100000的内容。可以看到0x7c00的时候,全都是空,此时没有数据,运行到0x0010000c处时,已经有数据了,说明已经加载了ELF的内容进内存了

GDB主要的命令是

b *0x7c00 # 0x7c00处设置断点
b *0x00100000 # 0x00100000处设置断点c # 继续执行代码到0x7c00处
x /8w 0x0010000 # 查看0x0010000内存处的内容
x /8w 0xf010000 # 查看 0xf010000 内存处的内容c # 继续执行代码到0x00100000处
x /8w 0x0010000 # 查看0x0010000内存处的内容
x /8w 0xf010000 # 查看 0xf010000 内存处的内容

Exercise 7

Exercise 7. Use QEMU and GDB to trace into the JOS kernel and stop at the movl %eax, %cr0. Examine memory at 0x00100000 and at 0xf0100000. Now, single step over that instruction using the stepi GDB command. Again, examine memory at 0x00100000 and at 0xf0100000. Make sure you understand what just happened.

What is the first instruction after the new mapping is established that would fail to work properly if the mapping weren’t in place? Comment out the movl %eax, %cr0 in kern/entry.S, trace into it, and see if you were right.

练习7其实跟练习6是类似的,是需要单步执行,去查看内核加载到底发生了什么。查看obj/kern/kernel.asm找到movl %eax, %cr0所在的地址,打一个断点,然后查看0x00100000和0xf0100000地址的内容,然后单步运行,在启用保护模式之后再查看两个地址的内容,就可以知道地址映射有区别

b *0x10000c # 在0x10000c设置断点,在入口处打断点
si # 单步执行
x /5w 0x0010000 # 查看内存内容
x /5w 0xf010000

Exercise 8

Exercise 8. We have omitted a small fragment of code - the code necessary to print octal numbers using patterns of the form “%o”. Find and fill in this code fragment.

练习8的目的是为了熟悉printfmt.c的代码。查阅kern/printf.c lib/printfmt.ckern/console.c的代码, 然后填充关于"%o"输出八进制的代码

具体代码如下:

case 'o':
// Replace this with your code.num = getuint(&ap, lflag);base = 8;goto number;    break;
  1. Explain the interface between printf.c and console.c. Specifically, what function does console.c export? How is this function used by printf.c?

console.c主要是在屏幕上输出内容,printf.c是根据不同的样式去打印输出,最终还是会调用console.c里面的内容

  1. Explain the following from console.c:
if (crt_pos >= CRT_SIZE) {int i;memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)crt_buf[i] = 0x0700 | ' ';crt_pos -= CRT_COLS;
}

代码是在console.c里面的cga_putc函数,而这部分是根据字符来输出什么内容的,但是当输出大于行的最大缓冲区时,会换行显示,所以这个代码片段就是这个作用

  1. For the following questions you might wish to consult the notes for Lecture 2. These notes cover GCC’s calling convention on the x86.

Trace the execution of the following code step-by-step:

int x = 1, y = 3, z = 4;
cprintf("x %d, y %x, z %d\n", x, y, z);

In the call to cprintf(), to what does fmt point? To what does ap point?

List (in order of execution) each call to cons_putc, va_arg, and vcprintf. For cons_putc, list its argument as well. For va_arg, list what ap points to before and after the call. For vcprintf list the values of its two arguments.

Lecture 2.对cprintf函数(定义在kern/printf.c)而言,fmt是一个指针,指向"x %d, y %x, z %d\n"这个【格式字符串】。而ap指向后面的变量列表var_list的起始地址,本例中可以理解为x的地址.

总之是利用一个函数内的所有东西大家都挤在一个栈区这个特点。最后的变量先入栈,最前的变量最后入栈,于是就成了栈顶。既然我们知道了第一个指针fmt的值,就很容易找到紧挨着的下一个位置ap的值,顺着ap一路找下去就能遍历整个var_list了

  1. Run the following code.
    unsigned int i = 0x00646c72;cprintf("H%x Wo%s", 57616, &i);
  1. What is the output? Explain how this output is arrived at in the step-by-step manner of the previous exercise. Here’s an ASCII table that maps bytes to characters.

The output depends on that fact that the x86 is little-endian. If the x86 were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?

Here’s a description of little- and big-endian and a more whimsical description.

输出He110 World由于是小端编码,所以0x00646c72对应存储的是72 6c 64 对应的ASCII码就是r l d, 57616对应的16进制是e110,所以输出是He110 World

其实可以把这个代码复制到kern/init.ci386_init函数中,去执行,也可以得到相同的答案。因为内核启动的时候,会在汇编中调用i386_init,所以在启动的时候,就可以看到运算结果

In the following code, what is going to be printed after ‘y=’? (note: the answer is not a specific value.) Why does this happen?

cprintf("x=%d y=%d", 3);

输出x=3 y=随机数 会把x所在地址+4Bit之后当作y的地址,然后取出这个数字打印,所以这个值是随机的。同样的也可以把代码贴进去验证

  1. Let’s say that GCC changed its calling convention so that it pushed arguments on the stack in declaration order, so that the last argument is pushed last. How would you have to change cprintf or its interface so that it would still be possible to pass it a variable number of arguments?

改变gcc压栈方式,in declaration order。 就是以声明的顺序,最早的变量最先入栈,到了栈底。这样栈顶指针,最后就指向了最后一个变量。此时可以添加一个计算变量总长度的参数size_t n。我们拿到栈顶指针ap之后,先 (void *)fmt = ap - n。就找到了格式化字符串的开头了。

Exercise 9

Exercise 9. Determine where the kernel initializes its stack, and exactly where in memory its stack is located. How does the kernel reserve space for its stack? And at which “end” of this reserved area is the stack pointer initialized to point to?

练习9主要是了解栈的初始化,栈的内存地址是位于哪里。主要是一个阅读内容。

x86栈指针(esp寄存器)指向当前正在使用栈的最低内存位置,保留区域中低于这个位置的都是可以使用的。入栈操作会先把栈指针变小,然后把这个值写入栈指针指向的位置。出栈动作是先从栈中读取数值,然后再把栈指针增加。在32位模式中,栈只能保存32位的数值,esp寄存器也总是被拆分成4个。不同的x86指令,例如call,是硬连接(hard-wired)使用栈指针寄存器的

Exercise 10

Exercise 10. To become familiar with the C calling conventions on the x86, find the address of the test_backtrace function in obj/kern/kernel.asm, set a breakpoint there, and examine what happens each time it gets called after the kernel starts. How many 32-bit words does each recursive nesting level of test_backtrace push on the stack, and what are those words?

Note that, for this exercise to work properly, you should be using the patched version of QEMU available on the tools page or on Athena. Otherwise, you’ll have to manually translate all breakpoint and memory addresses to linear addresses.

练习10的主要目的是看函数调用的时候,到底会保存哪些数据,需要在kern/init.ctest_backtrace的地方打断点调试查看

Exercise 11

Exercise 11. Implement the backtrace function as specified above. Use the same format as in the example, since otherwise the grading script will be confused. When you think you have it working right, run make grade to see if its output conforms to what our grading script expects, and fix it if it doesn’t. After you have handed in your Lab 1 code, you are welcome to change the output format of the backtrace function any way you like.

If you use read_ebp(), note that GCC may generate “optimized” code that calls read_ebp() before mon_backtrace()'s function prologue, which results in an incomplete stack trace (the stack frame of the most recent function call is missing). While we have tried to disable optimizations that cause this reordering, you may want to examine the assembly of mon_backtrace() and make sure the call to read_ebp() is happening after the function prologue.

就是实现backtrace函数,直接代码

int
mon_backtrace(int argc, char **argv, struct Trapframe *tf)
{uint32_t ebp, *ptr_ebp;ebp = read_ebp();cprintf("Stack backtrace:\n");while (ebp != 0) {ptr_ebp = (uint32_t *)ebp;cprintf("\tebp %x  eip %x  args %08x %08x %08x %08x %08x\n", ebp, ptr_ebp[1], ptr_ebp[2], ptr_ebp[3], ptr_ebp[4], ptr_ebp[5], ptr_ebp[6]);ebp = *ptr_ebp;}return 0;
}

主要是根据提示来改写 kern/monitor.c,重点用到的三个tricks:

利用read_ebp() 函数获取当前ebp值
利用 ebp 的初始值0判断是否停止
利用数组指针运算来获取 eip 以及 args

Exercise 12

Exercise 12. Modify your stack backtrace function to display, for each eip, the function name, source file name, and line number corresponding to that eip.

同样的也是实现,但是需要命令行输入,同时还要实现一个代码的二分查找

kern/kdebug.cdebuginfo_eip需要填充部分代码如下

// Hint:
//  There's a particular stabs type used for line numbers.
//  Look at the STABS documentation and <inc/stab.h> to find
//  which one.
// Your code here.
stab_binsearch(stabs, &lline, &rline, N_SLINE, addr);
if (lline <= rline) {info->eip_line = stabs[lline].n_desc;
} else {return -1;
}

最后再实现一下mon_backtrace就可以了,同时更新一下command就可以了

static struct Command commands[] = {{ "help", "Display this list of commands", mon_help },{ "kerninfo", "Display information about the kernel", mon_kerninfo },{"backtrace", "Backtrace monitor", mon_backtrace },
};int
mon_backtrace(int argc, char **argv, struct Trapframe *tf)
{// Your code here.uint32_t ebp, *ptr_ebp;struct Eipdebuginfo info;ebp = read_ebp();cprintf("Stack backtrace:\n");while (ebp != 0) {ptr_ebp = (uint32_t *)ebp;cprintf("ebp %x  eip %x  args %08x %08x %08x %08x %08x\n", ebp, ptr_ebp[1], ptr_ebp[2], ptr_ebp[3], ptr_ebp[4], ptr_ebp[5], ptr_ebp[6]);if (debuginfo_eip(ptr_ebp[1], &info) == 0) {uint32_t fn_offset = ptr_ebp[1] - info.eip_fn_addr;cprintf("\t\t%s:%d: %.*s+%d\n", info.eip_file, info.eip_line,info.eip_fn_namelen,  info.eip_fn_name, fn_offset);}ebp = *ptr_ebp;}return 0;
}

xv6实验1-启动计算机(实验)相关推荐

  1. 计算机中的二进制实验报告,大学计算机实验报告(共5篇).doc

    大学计算机实验报告(共5篇) 大学计算机实验报告(共5篇) 学号姓名:班级:实验时间: 实验报告表2-1 数值型数据在计算机中的二进制实验记录表 说明:本实验对计算机内存数据的存放拟定为:整数用两个字 ...

  2. 大一计算机学实验报告,大学计算机实验报告范文

    大学计算机实验报告范文 随着个人的文明素养不断提升,越来越多的事务都会使用到报告,通常情况下,报告的内容含量大.篇幅较长.写起报告来就毫无头绪?以下是小编帮大家整理的大学计算机实验报告,欢迎大家分享. ...

  3. 大学计算机实验教程实验6,大学计算机实验教程.第6版

    摘要: <大学计算机实验教程(第6版)/高等学校计算机基础教育教材精选>是"十一五"国家级规划教材,北京市教学成果奖教材,北京市精品教材<大学计算机教程(第6版) ...

  4. 大一大学计算机实验4,大学计算机实验教程(第4版)

    摘要: <大学计算机实验教程(第4版)/高等学校计算机基础教育教材精选·普通高等教育"十一五"国家级规划教材>是普通高等教育"十一五"国家级规划教材 ...

  5. 计算机综合实验报告范文,计算机实验报告范文(范文)

    PowerPoint 2003 演示文稿制作 1.实验性质:设计性实验 2.所属课程名称:大学计算机基础 3.实验计划学时:4 4.实验目的 1) 掌握 PowerPoint 2003 的基本界面和文 ...

  6. 大学计算机实验实验报告,大学计算机实验3 实验报告.doc

    文档介绍: 深圳大学实验报告 课程名称: 计算机基础 实验名称: 文字信息处理 学院: 建筑与城市规划学院专业: 建筑学 报告人: XXX 学号: 2015XXXX 班级: XXXXXX 同组人: 指 ...

  7. 大学计算机实验六实验报告,大学计算机实验6 实验报告.pdf

    深 圳 大 学 实 验 报 告 课程名称: 计算机基础 实验名称: 演示文稿制作 学院: 建筑与城市规划学院 专业: 建筑学 报告人: XXX 学号: 2015XXX 班级: XXXXXX 同组人: ...

  8. 计算机中的二进制实验报告,大学计算机-实验报告一.doc

    北京信息科技大学 信息管理学院 实 验 报 告 课程名称 信息系统基础 实验项目 实验一 计算机数据信息化和指令执行过程 实验仪器 PC.Office2003 专 业 **** 班级/学号 *** 学 ...

  9. 大学计算机一级实验报告,大学计算机实验报告范文

    摘要:本文从"互联网+"时代对各专业人才信息素养要求切入,重点阐述了新时代下"大学计算机"课程内容的构建及教学环节的组织与实施细节,最后给出教改经验及工作方向. ...

最新文章

  1. java图形用户界面添加背景颜色不成功的解决方案
  2. mysql as用法_MySQL基础学习总结
  3. 详细介绍如何在win7下首次实现通过Git bash向Github提交项目
  4. Android 应用软件开发(九)控件续
  5. g开头的C语言编程软件,C语言函数大全(g开头)
  6. Bzoj 3226: [Sdoi2008]校门外的区间
  7. python论文排版格式_学位论文排版教程2
  8. EEG时频分析介绍与实现
  9. 在线图书销售系统顺序图_苏宁易购网上商城在线购物
  10. iOS7 与 iOS8上 uisegementcontrol 设置image不显示问题
  11. WiMAX与Wi-Fi、DSL和3G的竞合关系
  12. 如何在word中的方框里打钩
  13. flask项目中出现Error: While importing ‘manager‘, an ImportError was raised.
  14. docker搭建XXLjob
  15. 双鱼林 android 服务器,双鱼林安卓Android代码生成器下载_双鱼林安卓Android代码生成器官方下载-太平洋下载中心...
  16. 神奇智能搜索引擎:perplexity智能搜索引擎(ChatGPT与Edge合体——联网版chatGPT)
  17. 固定翼飞机姿态角Backstepping反步法控制
  18. IPHONE视频软件测试,工具|6款视频剪辑APP测评
  19. 计算机中怎样重新安装ps,【2人回答】电脑要重装系统,不想重装Photoshop CS6,怎么办?-3D溜溜网...
  20. MySQL数据库基础操作(一)

热门文章

  1. 需求调研计划_三个公式,让你的2021年度培训计划更出彩
  2. IE11 安装 此更新不适应计算机
  3. 网易云课堂web安全学习第七天——了解url跳转漏洞
  4. Rasa原文-编写对话数据
  5. Zynq-7000系列之linux开发学习笔记:编译Linux内核和制作设备树(六)
  6. fluent中的压力
  7. java 锁升级_Java并发 锁优化和锁升级
  8. 史上最实用的文字转语音软件,没有之一
  9. 王者荣耀背景html,王者荣耀镜背景故事是什么?王者荣耀镜背景故事分享
  10. 503报错(nacos整合gateway网关)