Skip to content

Latest commit

 

History

History
93 lines (64 loc) · 6.85 KB

report.md

File metadata and controls

93 lines (64 loc) · 6.85 KB

Lab1实验报告

Linux内核

nproc输出cpu计算单元数量为12

按照实验主页先按默认选项编译,文件大小为17M

剪了网络,文件系统,各种驱动,不需要安全模块,不需要一些高级算法,多核支持等,到了6MiB以下(6MiB=6291456 Bytes, Image size=6203904 Bytes)

初始内存盘

如何在init进程中执行其他程序

按照"Operating System Concepts"中的init进程的fork()函数,并且调用execl()创建子进程并且依次执行1,2,3程序,wait()让父进程等待,调用exit(1)退出子进程

对于2,3

仿照实验主页中/dev/null字符设备的创建,以及mknod()的manual选择S_IFCHR | S_IRUSR | S_IWUSRmode,由已知,对/dev/ttyS0,makedev(4. 64),对/dev/ttyAMA0相应创建,对/dev/fb0makedev(29, 0)

...不知道讲义里的ttyS0ttyAMA0的或关系是什么意思,ttyS0不行,也许是内核模块里没有支持ttyS0 据树莓派官网的UART配置介绍,默认情况下启动UART0,类型为PL011,对应于/dev/ttyAMA0,要使用/dev/ttyS0,即使用miniUART,需要进行相应的配置。默认状态下enable_uart=1,使用UART0

使用循环来防止kernel panic

初识Boot

  • Makefile
    • $@: 目标文件
    • $^: 所有依赖文件
    • $<: 第一个依赖文件

Makefile步骤

  1. make boot.bin
  2. make loader.bin
  3. make kernel.bin
  4. make bootloader.img
  5. make qemu

make cleanmake cleanall挺好,然而我不清理

问题

非注释部分是我选择的,其他部分稍作了解,希望也能够帮我改一改,辛苦了

第一组问题

  • 1.xor ax, ax在将ax与其本身异或清零然后保存到ax寄存器中,好处是计算比数据移动要更快,更快的清零,在指令的大小和数量方面最快
  • 2.jmp $$表示取当前指令所在的地址,jmp $相当于不断将该指令的地址存入PC,形成死循环。只有当中断发生时,才会转去执行中断服务程序
  • 3.[es:di] es*16+di
  • 4.boot.asm文件前侧的org 0x7c00的用处是定义boot代码的绝对地址(比如在定义中断向量表的时候需要定义地址)
  • 5.times 510 - ($-$$) db0是在下面的代码中重复填入0共510-(当前指令地址-当前部分起始地址)次,原因是boot.asm最后的boot sector mark中是boot signature,BIOS在boot sector偏移510,511的地方找0x550xAA,通过times操作填充0可以方便在偏移510,511的位置写boot signature

第二组问题

  • 1.I am OK只要在loader的log_info GetMemStructOkMsg后面调用宏log_info IamOK, <字符串长度,不包括\0>, 4(第四行)即可,当然要在GetMemStructOkMsg下面写IamOK: db 'I am OK!'
  • 2.确定软盘可启动:通过fat12_find_file_in_root_dir来实现,如果找到了,就会进行后续的加载extry等操作,如果没有找到,就会失败,跳转到not_found。在fat12_find_in_root_dir中,主要通过对Sectorentry的循环实现顺序查找,通过比对文件名来实现
  • 3.为什么boot.asm2.之后可以继续执行loader.asm?原因是boot.asm中有jmp LoaderBase:LoaderOffset指令,而loader.asm的代码开始地址就是0x10000,所以jmp会跳转到LoaderBase*16+LoaderOffset的位置,刚好就是0x1000*16+0x0000 = 0x10000
  • 4.boot.asmloader.asm隔开的原因: - 同一个文件不能存在两个org,这样只能用times写,还要计算多少个0,很麻烦 - 如果将两个代码合在一起,在计算地址的时候就会很复杂,比如要修改boot部分的一点代码,可能就要涉及到很多的地址计算的修改。将两个代码在地址上分开方便维护,更新,修改。另外boot部分与loader部分对不同的硬件,不同的文件系统等,都要进行相应的修改,如果不分开,就很难维护,不如用jmp指令跳转来的方便 - 还有是放在两个文件里,标签可以重叠不会有影响,因为两个分开编译,方便写程序

思考题

  1. 在题目的范畴下,Linux应该主要指的是内核,它并不是一个完整的操作系统,而Ubuntu,Debian,Fedora,ArchLinux指Linux发行版。一个linux发行版除了包含linux内核外,通常还包含一系列GNU工具和库,一些附带软件,桌面系统等。不同的发行版用起来感觉可能完全不同,例如Arch系和Debian系的包管理器就有很大区别,在系统安装上也有很大差异,但是其内核是基本一致的(对不同发行版还是有细微差异)(参考了Linux101讲义)
  2. 不需要,因为我们在qemu上模拟,不需要SD卡。指导意义:init程序需要的如tty输出模块要保留,其他的一些可选模块基本都可以删去
  3. 树莓派启动阶段(BCM2837 based)
    1. 读取OTP(one-time programming)内存块决定哪种模式被启用
    2. SoC上ROM中的bootloader执行,挂在SD卡FAT32分区
    3. bootloader从SD卡上检查GPU固件,将固件写入GPU,随后启动GPU
    4. GPU启动后检索config.txt, fixup.dat,根绝其内容设置CPU参数和内存分配,然后加载用户代码,启动CPU
    5. 然后CPU执行内核程序
  1. config中写了enable_uart=1,不是只能用miniUART了吗?
  1. qemu-user中包含了qemu-arm,所以可以执行arm64busybox
    1. 具体过程:
      1. 在安装qemu-user的过程中会自动安装qemu-user-binfmt
      2. 安装了之后在/proc/sys/fs/binfmt_misc中就有很多条目,这些条目代表着各种指令的解释器,在我这里qemu-arm的解释器就是/usr/bin/qemu-arm
      3. 当直接执行./busybox时,kernel发现是ARM的elf格式,然后就使用/usr/bin/qemu-arm解释器(x86),来跑busybox,在本机上跑的实际是/usr/bin/qemu-arm这个解释器
    2. qemu-userqemu-system的区别就是qemu-user是运行单个程序文件,只有UserSpace emulation,而qemu-systemfull system emulation,包括UserSpace emulation,kernel emulationhardware emulationqemu-user相对更快

some reference

exec another process in one process

kernel panic

xor ax ax

UART config

qemu user mode & qemu-system

希望改完能提点issue