基于ucore的操作系统实验lab1

基于ucore的操作系统实验lab1

[练习1]

练习1.1

1、先编译链接生成kernel文件
2、再编译链接生成bootblock文件
3、生成ucore.imgsign.c生成bootblock
1.2 查看sign.c可以发现关键在于bootblock.out小于510bytes,且 buf[510] = 0x55; buf[511] = 0xAA;

[练习2]

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

单步跟踪,方法如下:

1 修改 lab1/tools/gdbinit,内容为:


set architecture
i8086

target remote
:1234

2 在 lab1目录下,执行


make debug

3 在看到gdb的调试界面(gdb)后,在gdb调试界面下执行如下命令


si

即可单步跟踪BIOS了。

4 在gdb界面下,可通过如下命令来看BIOS的代码


 x /2i $pc 
//显示当前eip处的汇编指令
练习2.2 在初始化位置0x7c00设置实地址断点,测试断点正常。

在gdb中输入一下命令

    b *0x7c00 
//在0x7c00处设置断点。此地址是bootloader入口点地址,可看boot/bootasm.S的start地址处

    c         
//continue简称,表示继续执行

    x /2i $pc 
//显示当前eip处的汇编指令

得到
Breakpoint 2,
0x00007c00 in ?? ()

=> 0x7c00:      cli   


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

将2.2中的步骤重复实现与两个文件进行对比发现是一致的

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

自己按以上步骤测试一下就行了

练习3

练习3.1 分析bootloader进入保护模式的过程。

它先将各个寄存器置0

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

初始化GDT表:一个简单的GDT表和其描述符已经静态储存在引导区中,载入即可


       
lgdt gdtdesc

进入保护模式:通过将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

转到保护模式完成,进入boot主方法


       
call bootmain

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

首先看readsect函数,

readsect从设备的第secno扇区读取数据到dst位置


       static
void

       readsect(void
*dst, uint32_t secno) {

           waitdisk();

       

           outb(0x1F2, 1);                         // 设置读取扇区的数目为1

           outb(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为单位

       }

readseg简单包装了readsect,可以从设备读取任意长度的内容。


       static
void

       readseg(uintptr_t
va, uint32_t count, uint32_t offset) {

           uintptr_t end_va = va + count;

       

           va -= offset % SECTSIZE;

       

           uint32_t secno = (offset / SECTSIZE) + 1; 

           // 加1因为0扇区被引导占用

           // ELF文件从1扇区开始

       

           for (; va < end_va; va += SECTSIZE,
secno ++) {

               readsect((void *)va, secno);

           }

       }

在bootmain函数中,


       void

       bootmain(void)
{

           // 首先读取ELF的头部

           readseg((uintptr_t)ELFHDR, SECTSIZE * 8,
0);

       

           // 通过储存在头部的幻数判断是否是合法的ELF文件

           if (ELFHDR->e_magic != ELF_MAGIC) {

               goto bad;

           }

       

           struct proghdr *ph, *eph;

       

           // ELF头部有描述ELF文件应加载到内存什么位置的描述表,

           // 先将描述表的头地址存在ph

           ph = (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

实现函数调用堆栈跟踪函数

ss:ebp指向的堆栈位置储存着caller的ebp,以此为线索可以得到所有使用堆栈的函数ebp。

ss:ebp+4指向caller调用时的eip,ss:ebp+8等是(可能的)参数。

输出中,堆栈最深一层为


       ebp:0x00007bf8
eip:0x00007d68 \

              args:0x00000000
0x00000000 0x00000000 0x00007c4f

           <unknow>: -- 0x00007d67 --

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值