6.S081 Lab00 xv6启动过程(从代码出发,了解操作系统启动过程)

6.S081 Lab00 xv6启动过程

0. 说明与简介

说明:这里为了和lab 0区分用了lab 00来代替,以后还可能会有Lab 000 (xv6的启动代码分析 – bios)

主要内容:简单的介绍XV6是如何从0开始直到第一个Shell程序运行起来

如果时间不够,可以只看3.关键知识点总结

1. 调试命令

(1) gdb开启qemu的调试

首先在xv6-riscv目录下,运行命令make CPUS=1 qemu-gdb

注意:这里为什么是 CPUS = 1–为了方便调试,我们把CPU设置为1,而不是默认的4(正如前面6.S081-2内核的隔离性(isolation)所讲,qemu模拟的riscv是4核的)。 在单核或者单线程场景下,单个断点就可以停止整个程序的运行。

wc@r740:~/OS_experiment/xv6-riscv-fall19$ make CPUS=1 qemu-gdb
sed "s/:1234/:26017/" < .gdbinit.tmpl-riscv > .gdbinit
*** Now run 'gdb' in another window.
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 1 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 -S -gdb tcp::26017

(2) 开启gdb

然后根据提示,Now run ‘gdb’ in another window. – 在新的terminal下,打开gdb进行调试,调试命令如下

(注意最后一行的tcp::26017这点后面要用到(可能你的端口数字未必和我一样,后面用自己的端口号就行))

$ riscv64-unknown-elf-gdb kernel/kernel

运行上面命令后可以看到一大堆输出,如果此时最后一行变成了(gdb)说明我们成功进入了gdb。但是我们还没有成功进入调试环境!!!– 这里还是主机环境上的gdb,但是想要调试xv6的kernel,需要在riscv的机器上进行。

(3) 将gdb远程连接到qemu上

在新打开的gdb环境下,远程链接qemu (这里的26017是tcp的端口号,来源于make CPUS=1 qemu-gdb命令的最后一行输出,因为自己电脑上的某些端口可能被占用,因此这个端口号每个人或许不同,请注意修改)

(gdb) target remote localhost:26017

结果为

Remote debugging using localhost:26017
0x0000000000001000 in ?? ()

以上结果表示成功进入gdb,接下来可以对kernel进行调试。这部分可以参考 HITSZ_OS手册

# b //设置断点(breakpoint)
# c //继续运行(Continue)--到断点处就会停止
# n //单步调试 
# p //打印变量内容
# si //断点定位
# display/i $pc //每次停止时,都可以显示下一条指令的反汇编
# layout asm //可以显示当前的汇编指令
# display /3i $pc //如果您希望在单步执行程序时自动显示下3条指令,可以使用display命令
# p *path@6 //这里是打印path指向的内容,打印长度为6(如果不写@6那么只能打印一个char)

2. 设置断点,进行调试

(0) 第一条指令的执行 + 第一个断点 (运行在machine mode)

首先是在_entry处设置断点(因为_entry是kernel的第一条指令 – 可以通过查看kernel.asm查看)

kernel.asm (内核的汇编代码)部分代码如下:

kernel/kernel:     file format elf64-littleriscv


Disassembly of section .text:

0000000080000000 <_entry>:
    80000000:	0000b117          	auipc	sp,0xb
    80000004:	80010113          	addi	sp,sp,-2048 # 8000a800 <stack0>
    80000008:	6505                	lui	a0,0x1
    8000000a:	f14025f3          	csrr	a1,mhartid
    8000000e:	0585                	addi	a1,a1,1
    80000010:	02b50533          	mul	a0,a0,a1
    80000014:	912a                	add	sp,sp,a0
    80000016:	070000ef          	jal	ra,80000086 <start>

000000008000001a <junk>:
    8000001a:	a001                	j	8000001a <junk>

000000008000001c <timerinit>:
// which arrive at timervec in kernelvec.S,
// which turns them into software interrupts for
// devintr() in trap.c.
void
timerinit()
{
   
   
    8000001c:	1141                	addi	sp,sp,-16
    8000001e:	e422                	sd	s0,8(sp)
    80000020:	0800                	addi	s0,sp,16
// which hart (core) is this?
static inline uint64
  • 设置断点,并继续运行代码到断点处,如下:
(gdb) b _entry
Breakpoint 1 at 0x8000000a
(gdb) c
Continuing.

Breakpoint 1, 0x000000008000000a in _entry ()

可以看到,我们并没有停在0x80000000 (即_entry处),而是停在了0x8000000a

问题:为什么第一条指令的地址是0x80000000???

0x80000000是一个被qemu认可的地址,如果想要使用qemu,第一条指令就必须在0x80000000

这一点可以打开kernel.ld查看(关于kernel.ld的分析,可以看好文链接

OUTPUT_ARCH( "riscv" )
ENTRY( _entry )

SECTIONS
{
   
   
  /*
   * ensure that entry.S / _entry is at 0x80000000,
   * where qemu's -kernel jumps.
   */
  . = 0x80000000;
  .text :
  {
   
   
    *(.text)
    . = ALIGN(0x1000);
    *(trampsec)
  }

  . = ALIGN(0x1000);
  PROVIDE(etext = .);

  /*
   * make sure end is after data and bss.
   */
  .data : {
   
   
    *(.data)
  }
  .bss : {
   
   
    *(.bss)
    *(.sbss*)
     PROVIDE(end = .);
  }
}
  • 回到gdb中,可以看到已经在_entry里面了, 0x8000000a处的汇编代码为:csrr a1,mhartid 它的长度是:2B。因此它的下一条指令地址为:0x000000008000000e,对应的汇编是:addi a1,a1,1.

(1) main() 的执行 (进入kernel mode)

  • 接下来继续打一个断点在main()处,可以得到如下结果 (XV6从entry.s开始启动,这个时候没有内存分页,没有隔离性,并且运行在M-mode(machine mode)。XV6会尽可能快的跳转到kernel mode或者说是supervisor mode。我们在main函数设置一个断点,main函数已经运行在supervisor mode了。接下来我运行程序,代码会在断点,也就是main函数的第一条指令停住。)
26017: No such file or directory.
(gdb) target remote localhost:26017
Remote debugging using localhost:26017
0x0000000000001000 in ?? ()
(gdb) b _entry
Breakpoint 1 at 0x8000000a
(gdb) display/i $pc
1: x/i $pc
=> 0x1000:      auipc   t0,0x0
(gdb) c
Continuing.

Breakpoint 1, 0x000000008000000a in _entry 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值