操作系统-ucore-lab1

合集下载

操作系统-ucore-lab3

操作系统-ucore-lab3

操作系统-ucore-lab3操作系统实验报告题⽬:虚拟内存管理⽬录⼀、内容 (2)⼆、⽬的 (3)三、实验流程 (3)四、实验环境与结果分析 (3)五、实验体会和思考题 (10)⼀、内容本次实验是在实验⼆的基础上,借助于页表机制和实验⼀中涉及的中断异常处理机制,完成Page Fault异常处理和FIFO页替换算法的实现,结合磁盘提供的缓存空间,从⽽能够⽀持虚存管理,提供⼀个⽐实际物理内存空间“更⼤”的虚拟内存空间给系统使⽤。

这个实验与实际操作系统中的实现⽐较起来要简单,不过需要了解实验⼀和实验⼆的具体实现。

实际操作系统系统中的虚拟内存管理设计与实现是相当复杂的,涉及到与进程管理系统、⽂件系统等的交叉访问。

如果⼤家有余⼒,可以尝试完成扩展练习,实现extended clock页替换算法。

练习1:给未被映射的地址映射上物理页(需要编程)完成do_pgfault(mm/vmm.c)函数,给未被映射的地址映射上物理页。

设置访问权限的时候需要参考页⾯所在VMA的权限,同时需要注意映射物理页时需要操作内存控制结构所指定的页表,⽽不是内核的页表。

注意:在LAB2EXERCISE1处填写代码。

执⾏make qemu后,如果通过check_pgfault函数的测试后,会有“check_pgfault() succeeded!”的输出,表⽰练习1基本正确。

请在实验报告中简要说明你的设计实现过程。

请回答如下问题:请描述页⽬录项(Pag Director Entry)和页表(Page Table Entry)中组成部分对ucore实现页替换算法的潜在⽤处。

如果ucore的缺页服务例程在执⾏过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?练习2:补充完成基于FIFO的页⾯替换算法(需要编程)完成vmm.c中的do_pgfault函数,并且在实现FIFO算法的swap_fifo.c中完成map_swappable和swap_out_vistim函数。

Ucore-操作系统实验六

Ucore-操作系统实验六

Ucore-操作系统实验六
Ucore-操作系统实验六
1、实验背景
1.1 Ucore操作系统简介
1.2 进程调度算法简介
2、实验目的
2.1 理解进程调度算法的概念和原理
2.2 学习设计和实现进程调度算法
2.3 掌握在Ucore操作系统中实现进程调度算法的方法
3、实验要求
3.1 设计一个合适的进程调度算法
3.2 修改Ucore操作系统的源代码,实现设计的进程调度算法
3.3 运行并测试实现的进程调度算法,确保其功能正确性
4、实验内容
4.1 理解Ucore操作系统的进程管理模块
4.2 设计进程调度算法
4.3 修改进程管理模块的源代码,实现进程调度算法
4.4 编译并运行修改后的Ucore操作系统,进行测试和验证
5、实验步骤
5.1 分析Ucore操作系统的进程管理模块,了解其结构和功能
5.2 设计进程调度算法,考虑算法的可行性和性能
5.3 基于设计的算法,修改进程管理模块的源代码,实现进程调度算法
5.4 编译并运行修改后的Ucore操作系统,进行测试和验证
6、实验结果分析
6.1 比较不同进程调度算法在Ucore操作系统中的性能差异
6.2 分析实验结果,总结优缺点
附件:
- Ucore操作系统源代码:zip
法律名词及注释:
1、版权:指对原创作品(如文学、艺术、音乐、软件等)的独特权利保护。

著作权法是一种保护版权的法律。

2、开源:指软件或硬件的设计和制造过程中,公开的原始设计数据、设计文档、设计过程以及产品源代码等。

3、许可证:是指著作权人授予他人使用其作品或知识产权的权利的行为。

Lab1 介绍

Lab1 介绍

如何进入保护模式

boot/boot.s
lgdt gdtdesc 重新加载gdt表 movl %cr0, %eax orl $CR0_PE_ON, %eax movl %eax, %cr0 设置cr0寄存器,开启保护模式 ljmp $PROT_MODE_CSEG, $protcseg 进入32位模式 .code32 protcseg: # Assemble for 32-bit mode

8个16-bit寄存器( 8个32-bit寄存器的低16位)

8个8-bit寄存器(%ax ~%dx的高8位和低8位)

6个段寄存器

3个控制寄存器

AT&T汇编语法(2)——立即数

使用立即数,要在数前面加符号$

$0x04 \lab1\boot\boot.S
(1)
testb$0x2,%al .set CR0_PE_ON,0x1 orl $CR0_PE_ON, %eax
ELF文件结构
如何在ELF中找到某一段
重要的数据结构 ELF文件头: struct Elf{} 程序头表相对于文件开头的偏 移: Elf->e_phoff 程序头表中段个数: Elf->e_phnum 程序头表中的段: struct Proghdr 段相对于文件开头的偏移: Proghdr->p_offset
AT&T汇编语法(5)——内存寻址

寻址方式

AT&T: displacement(base,index,scale) Intel: [base+index*scale+displacement] -4(%ebp)

清华大学操作系统实验lab1实验报告

清华大学操作系统实验lab1实验报告

练习1、理解通过make生成执行文件的过程。

[练习1.1] 操作系统镜像文件ucore.img 是如何一步一步生成的?在proj1执行命令make V=可以得到make指令执行的过程从这几条指令中可以看出需要生成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,0xAAbuf[510] = 0x55;buf[511] = 0xAA;FILE *ofp = fopen(argv[2], "wb+");size = fwrite(buf, 1, 512, ofp);[练习1.2] 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?前面已经提到过:引导扇区的大小为512字节,最后两个字节为标志性结束字节0x55,0xAA,做完这样的检查才能认为是符合规范的磁盘主引导扇区。

Sign.c文件中有作检查:if (size != 512) {fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size);return -1;}练习2:使用qemu执行并调试lab1中的软件。

清华大学操作系统lab1_实验报告

清华大学操作系统lab1_实验报告

实验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 $< -serial null"$(V)sleep 2$(V)$(TERMINAL) -e "gdb -q -x tools/lab1init"在调用qemu时增加-d in_asm -D q.log参数,便可以将运行的汇编指令保存在q.log 中。

(2)在初始化位置0x7c00 设置实地址断点,测试断点正常。

在tools/gdbinit结尾加上set architecture i8086b *0x7c00 //在0x7c00处设置断点。

continuex /2i $pc //显示当前eip处的汇编指令(3)将执行的汇编代码与bootasm.S 和bootblock.asm 进行比较,看看二者是否一致。

Notice:在q.log中进入BIOS之后的跳转地址与实际应跳转地址不相符,汇编代码也与bootasm.S 和bootblock.asm不相同。

北京大学操作系统实习JOS lab1实验笔记

北京大学操作系统实习JOS lab1实验笔记

OS_lab1最近编辑过的 2011年3月14日系统启动过程:1. 开机以后,计算机将CS=0xF000, IP=0xFFF0, 物理地址为0xFFFF0,这个位置是BIOS ROM所在位置(0xF0000~0xFFFFF),所以机器一开始控制权交给BIOS2. BIOS接到控制权以后,肯定跳转,因为0xFFFF0到0xFFFFF就1Byte信息,这个无法做任何事,所以跳到前面位置开始运行3. BIOS做的工作主要是初始化一些关键的寄存器和中断开关,做完后,BIOS从IDE硬盘第一个扇区512Byte读入boot loader到内存的0x7c00到0x7dff,然后设置CS=0x0000, IP=0x7c00,控制权交给boot loader4. boot loader的任务是将处理器从实模式切换到保护模式,然后将内核kernel从硬盘上读取到内存中,然后切换到内核开始启动操作系统5. kernel放置在硬盘上,在JOS中是存在在了紧接在boot loader的第二个扇区里,如果想修改位置的话,需要修改产生硬盘镜像的kern/Makefrag文件,看到第73行:68 # How to build the kernel disk image69 $(OBJDIR)/kern/kernel.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot70 @echo + mk $@71 $(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null72 $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null73 $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null74 $(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.img75seek = 1表示是硬盘上第二个扇区,72行将boot即是将boot loader放入第一扇区。

ucore操作系统学习(二)ucorelab2物理内存管理分析

ucore操作系统学习(二)ucorelab2物理内存管理分析

ucore操作系统学习(⼆)ucorelab2物理内存管理分析⼀、lab2物理内存管理介绍 操作系统的⼀个主要职责是管理硬件资源,并向应⽤程序提供具有良好抽象的接⼝来使⽤这些资源。

⽽内存作为重要的计算机硬件资源,也必然需要被操作系统统⼀的管理。

最初没有操作系统的情况下,不同的程序通常直接编写物理地址相关的指令。

在多道并发程序的运⾏环境下,这会造成不同程序间由于物理地址的访问冲突,造成数据的相互覆盖,进⽽出错、崩溃。

现代的操作系统在管理内存时,希望达到两个基本⽬标:地址保护和地址独⽴。

地址保护指的是⼀个程序不能随意的访问另⼀个程序的空间,⽽地址独⽴指的是程序指令给出的内存寻址命令是与最终的物理地址⽆关的。

在实现这两个⽬标后,便能够为多道并发程序运⾏时的物理内存访问的隔离提供⽀持。

每个程序在编译、链接后产⽣的最终机器代码都可以使⽤完整的地址空间(虚拟地址),⽽不需要考虑其它的程序的存在。

ucore通过两个连续的实验迭代,lab2和lab3分别实现了物理内存管理和虚拟内存管理(利⽤磁盘缓存⾮⼯作集内存,扩展逻辑上的内存空间)。

ucore的每个实验都是建⽴在前⼀个实验迭代的基础上的,要想更好的理解lab2,最好先理解之前lab1中的内容()。

lab2在lab1平坦模型段机制的基础上,开启了80386的分页机制,并建⽴了内核页表;同时通过硬件中断探测出了当前内存硬件的布局,并以此为依据根据可⽤的内存建⽴了⼀个物理内存管理框架,通过指定某种分配算法,负责处理所有的物理内存页分配与释放的请求。

lab2的代码结构和执⾏流程与lab1差别不⼤,其主要新增了以下功能: 1. bootmain.S中的物理内存探测 2. 在新增的entry.S内核⼊⼝程序中开启了80386页机制 3. kern_init内核总控函数中通过pmm_init函数进⾏整个物理内存管理器的构建初始化⼆、lab2实验细节分析2.1 物理内存布局探测 为了进⾏物理内存的管理,操作系统必须先探测出当前硬件环境下内存的布局,了解具体哪些物理内存空间是可⽤的。

哈工大《操作系统》实验1

哈工大《操作系统》实验1

(5)重新编写一个setup.s,然后将其中的显示的信息改为:“Now we are in SETUP”。

再次编译,重新用make命令生成BootImage,结合提示信息和makefile文修改build.c,具体将setup.s改动如下:mov cx,#27mov bx,#0x0007 ! page 0, attribute 7 (normal)mov bp,#msg1mov ax,#0x1301 ! write string, move cursorint 0x10dieLoop:j dieLoopmsg1:.byte 13,10,13,10.ascii "Now we are in SETUP".byte 13,10,13,10将build.c改动如下:if(strcmp("none",argv[3]) == 0)//添加判断return 0;if ((id=open(argv[3],O_RDONLY,0))<0)die("Unable to open 'system'");// if (read(id,buf,GCC_HEADER) != GCC_HEADER)// die("Unable to read header of 'system'");// if (((long *) buf)[5] != 0)// die("Non-GCC header of 'system'");for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )if (write(1,buf,c)!=c)die("Write call failed");close(id);fprintf(stderr,"System is %d bytes.\n",i);if (i > SYS_SIZE*16)die("System is too big");return(0);(6)验证:用make是否能成功生成BootImage,运行run命令验证运行结果。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

HUNAN UNIVERSITY操作系统实验报告目录一、内容 (2)二、目的 (2)三、实验设计思想和流程 (3)四、主要文件结构说明 (4)五、实验环境以及实验过程与结果分析(包含实验详细过程) (4)练习1:理解通过make生成执行文件的过程 (4)练习2:使用qemu执行并调试lab1中的软件。

(6)练习3:分析bootloader进入保护模式的过程。

(9)练习4:分析bootloader加载ELF格式的OS的过程。

(11)练习5:实现函数调用堆栈跟踪函数 (14)练习6:完善中断初始化和处理 (16)六、实验体会 (18)一、内容lab1中包含一个bootloader和一个OS。

这个bootloader可以切换到X86保护模式,能够读磁盘并加载ELF执行文件格式,并显示字符。

而这lab1中的OS只是一个可以处理时钟中断和显示字符的幼儿园级别OS。

为了实现lab1的目标,lab1提供了6个基本练习和1个扩展练习,要求完成实验报告。

二、目的操作系统是一个软件,也需要通过某种机制加载并运行它。

在这里我们将通过另外一个更加简单的软件-bootloader来完成这些工作。

为此,我们需要完成一个能够切换到x86的保护模式并显示字符的bootloader,为启动操作系统ucore做准备。

lab1 提供了一个非常小的bootloader和ucore OS,整个bootloader执行代码小于512个字节,这样才能放到硬盘的主引导扇区中。

通过分析和实现这个bootloader和ucore OS,读者可以了解到:计算机原理CPU的编址与寻址: 基于分段机制的内存管理CPU的中断机制外设:串口/并口/CGA,时钟,硬盘Bootloader软件编译运行bootloader的过程调试bootloader的方法PC启动bootloader的过程ELF执行文件的格式和加载外设访问:读硬盘,在CGA上显示字符串ucore OS软件编译运行ucore OS的过程ucore OS的启动过程调试ucore OS的方法函数调用关系:在汇编级了解函数调用栈的结构和处理过程中断管理:与软件相关的中断处理外设管理:时钟三、实验设计思想和流程依照实验指导书完成了六个对应练习:练习1:理解通过make生成执行文件的过程练习2:使用qemu执行并调试lab1中的软件练习3:分析bootloader进入保护模式的过程练习4:分析bootloader加载ELF格式的OS的过程练习5:实现函数调用堆栈跟踪函数练习6:完善中断初始化和处理四、主要文件结构说明五、实验环境以及实验过程与结果分析(包含实验详细过程)实验环境为:LINUX_64系统。

练习1:理解通过make生成执行文件的过程1.操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)# create ucore.imgUCOREIMG := $(call totarget,ucore.img)$(UCOREIMG): $(kernel) $(bootblock)$(V)dd if=/dev/zero of=$@ count=10000$(V)dd if=$(bootblock) of=$@ conv=notrunc$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc$(call create_target,ucore.img)//为了生成bootblock,首先需要生成bootasm.o、bootmain.o、sign$(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign) @echo + ld $@$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock) @$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock) @$(call totarget,sign) $(call outfile,bootblock) $(bootblock)$(call create_target,bootblock)(1)通过GCC编译器将Kernel目录下的.c文件编译成OBJ目录下的.o文件。

(2)ld命令根据链接脚本文件kernel.ld将生成的*.o文件,链接成BIN目录下的kernel文件(3)通过GCC编译器将boot目录下的.c, .S文件以及tools目录下的sign.c文件编译成OBJ 目录下的*.o文件。

(4)ld命令将生成的*.o文件,链接成BIN目录下的bootblock文件。

(5)dd命令将dev/zero, bin/bootblock,bin/kernel 写入到bin/ucore.img注:/dev/zero文件代表一个永远输出 0的设备文件,使用它作输入可以得到全为空的文件。

因此可用来创建新文件和以覆盖的方式清除旧文件。

下面使用dd命令将从zero设备中创建一个10K大小(bs决定每次读写1024字节,count定义读写次数为10次),但内容全为0的文件。

dd 是 Linux/UNIX 下的一个非常有用的命令,作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。

2.一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?从以下代码可以看出:buf缓冲区最后两位为0x55和0xAA,并且需要扇区大小满足512字节。

(1) 编译过程:在解压缩后的ucore 源码包中使用make 命令即可。

例如lab1中:chy@laptop: ~/lab1$ make在lab1目录下的bin目录中,生成一系列的目标文件:ucore.img:被qemu访问的虚拟硬盘文件kernel: ELF格式的toy ucore kernel执行文,被嵌入到了ucore.img中bootblock: 虚拟的硬盘主引导扇区(512字节),包含了bootloader执行代码,被嵌入到了ucore.img中sign:外部执行程序,用来生成虚拟的硬盘主引导扇区还生成了其他很多文件,这里就不一一列举了。

练习2:使用qemu执行并调试lab1中的软件。

从CPU加电后执行的第一条指令开始,单步跟踪BIOS的执行。

1.在初始化位置0x7c00设置实地址断点,测试断点正常。

2.3. 从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和bootblock.asm进行比较。

(1)修改Makefile中debug段代码,使其默认执行如下命令:-S -s$(V)$(QEMU) -e “$(QEMU) –S –s –d in_asm –D $(BINDIR)/q.log -parallel stdio -hda $< -serial null “为了与qemu配合进行源代码级别的调试,需要先让qemu进入等待gdb调试器的接入并且还不能让qemu中的CPU执行,因此启动qemu的时候,我们需要使用参数-S、–s这两个参数来做到这一点。

修改gdbinit文件如下:执行make debug(2)q.log(3)q.log与bootasm.S和bootblock.asm中的代码相同。

4. 自己找一个bootloader或内核中的代码位置,设置断点并进行测试。

修改debuginit如下:断点设置正常:练习3:分析bootloader进入保护模式的过程。

BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader。

请分析bootloader是如何完成从实模式进入保护模式的。

//关中断和清除段数据:包括将flag置0和将段寄存器置0.globl startstart:.code16cli //关中断cld //清除方向标志xorw %ax, %ax //ax清0movw %ax, %ds //ds清0movw %ax, %es //es清0movw %ax, %ss //ss清0开启A20:通过将键盘控制器上的A20线置于高电位,全部32条地址线可用,可以访问4G的内存空间。

seta20.1: # 等待8042键盘控制器不忙inb $0x64, %al #testb $0x2, %al #jnz seta20.1 #movb $0xd1, %al # 发送写8042输出端口的指令outb %al, $0x64 #seta20.1: # 等待8042键盘控制器不忙inb $0x64, %al #testb $0x2, %al #jnz seta20.1 #movb $0xdf, %al # 打开A20outb %al, $0x60 #初始化GDT表:一个简单的GDT表和其描述符已经静态储存在引导区中,载入即可lgdt gdtdesc进入保护模式:通过将cr0寄存器PE位置1便开启了保护模式movl %cr0, %eaxorl $CR0_PE_ON, %eaxmovl %eax, %cr0通过长跳转更新cs的基地址ljmp $PROT_MODE_CSEG, $protcseg.code32protcseg:设置段寄存器,并建立堆栈movw $PROT_MODE_DSEG, %axmovw %ax, %dsmovw %ax, %esmovw %ax, %fsmovw %ax, %gsmovw %ax, %ssmovl $0x0, %ebpmovl $start, %esp转到保护模式完成,进入boot主方法call bootmain练习4:分析bootloader加载ELF格式的OS的过程。

通过阅读bootmain.c,了解bootloader如何加载ELF文件。

通过分析源代码和通过qemu来运行并调试bootloader&OSbootloader如何读取硬盘扇区的?bootloader是如何加载ELF格式的OS?要了解bootloader是如何读取硬盘扇区的需要了解elf.h文件读取扇区static voidreadsect(void *dst, uint32_t secno) {waitdisk();outb(0x1F2, 1); // 设置读取扇区的数目为1outb(0x1F3, secno & 0xFF);outb(0x1F4, (secno >> 8) & 0xFF);outb(0x1F5, (secno >> 16) & 0xFF);outb(0x1F6, ((secno >> 24) & 0xF) | 0xE0);// 上面四条指令联合制定了扇区号// 在这4个字节线联合构成的32位参数中// 29-31位强制设为1// 28位(=0)表示访问"Disk 0"// 0-27位是28位的偏移量outb(0x1F7, 0x20); // 0x20命令,读取扇区waitdisk();insl(0x1F0, dst, SECTSIZE / 4); // 读取到dst位置,// 幻数4因为这里以DW为单位}/* file header */struct elfhdr {uint32_t e_magic; // must equal ELF_MAGIC elf的模数uint8_t e_elf[12];uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core imageuint16_t e_machine; // 3=x86, 4=68K, etc.uint32_t e_version; // file version, always 1uint32_t e_entry; // entry point if executable 入口地址uint32_t e_phoff; // file position of program header or 0第一个programheader的位置,//这是个结构体,通过这个指针可以找到结构体数组的位置结合e_phnum可以取得所有ph结构体uint32_t e_shoff; // file position of section header or 0uint32_t e_flags; // architecture-specific flags, usually 0uint16_t e_ehsize; // size of this elf headeruint16_t e_phentsize; // size of an entry in program headeruint16_t e_phnum; // number of entries in program header or 0uint16_t e_shentsize; // size of an entry in section headeruint16_t e_shnum; // number of entries in section header or 0uint16_t e_shstrndx; // section number that contains section name strings};/* program section header */struct proghdr {uint32_t p_type; // loadable code or data, dynamic linking info,etc.uint32_t p_offset; // file offset of segmentuint32_t p_va; // virtual address to map segmentuint32_t p_pa; // physical address, not useduint32_t p_filesz; // size of segment in fileuint32_t p_memsz; // size of segment in memory (bigger if contains bss)uint32_t p_flags; // read/write/execute bitsuint32_t p_align; // required alignment, invariably hardware page size };bootloader如何加载ELF格式的OS:在bootmain函数中,voidbootmain(void) {// 首先读取ELF的头部readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);// 通过储存在头部的幻数判断是否是合法的ELF文件if (ELFHDR->e_magic != ELF_MAGIC) {goto bad;}struct proghdr *ph, *eph;// ELF头部有描述ELF文件应加载到内存什么位置的描述表,// 先将描述表的头地址存在phph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);eph = ph + ELFHDR->e_phnum;// 按照描述表将ELF文件中数据载入内存for (; ph < eph; ph ++) {readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);}// ELF文件0x1000位置后面的0xd1ec比特被载入内存0x00100000// ELF文件0xf000位置后面的0x1d20比特被载入内存0x0010e000// 根据ELF头部储存的入口信息,找到内核的入口((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();bad:outw(0x8A00, 0x8A00);outw(0x8A00, 0x8E00);while (1);}练习5:实现函数调用堆栈跟踪函数我们需要在lab1中完成kdebug.c中函数print_stackframe的实现,可以通过函数print_stackframe来跟踪函数调用堆栈中记录的返回地址。

相关文档
最新文档