Ucore Lab0 on Apple Silicon Mac

Ucore Lab0 on Apple Silicon Mac

介绍

M1芯片是2020年之后推出的全新适配于Macbook的Arm64芯片。因为底层的指令集与x86_64不同,因此面临着很多兼容性的问题。在ucore的编译,运行和调试的环境配置中也因此踩了一些坑。当然最终得以能够优雅的在这台具有独特架构的PC上探索实现操作系统的魅力。

现在将其记录下来,以供参考。

qemu安装

qemu是非常成熟的虚拟化解决方案,通过软件的方式逐条将目标文件的二进制指令翻译成目标架构支持的二进制指令,虽然效率不高,但是使用方便,对M1芯片支持也比较完善,足够用来调试ucore了。

指导书中针对linux给出了使用包管理工具的安装方案。在mac上这个过程也同样比较简单。安装homebrew包管理工具后只需要

shell
brew install qemu

即可。当然为了保证是最新版本,安装之前可以更新一下homebrew:brew update

i386-elf-gcc和i386-elf-gdb安装

按照网上的解决方案,我安装了macport,并

shell
sudo port -v selfupdate
sudo port install i386-elf-gcc

但是发现它安装过程中构建失败了。

image-20221003224714488

查看发现果然是架构问题:

image-20221003224809467

查看报错信息。谷歌后从github issue中得知是有支持apple silicon版本的最新i386-elf-gcc的。

image-20221003225239013
image-20221003225245971

有希望!但是按官网命令安装问题也没有解决,所谓补丁也不起效。后来尝试用homebrew安装:brew install i386-elf-gdb,但没有安装成功。提示

awk
fatal: not in a git directory Error: Command failed with exit 128: git

又经过一番谷歌找到了解决方法。执行

shell
git config --global --add safe.directory 报错信息中homebrew-core路径
git config --global --add safe.directory 报错信息中homebrew-cask路径

即可。

然后需要添加一下环境变量。

这时尝试qemu生成ucore的dmg,发现提示i386-elf-gcc找不到。这才注意到通过homebrew下载的是x86_64-elf-gcc

经过搜索,得知在make时需要添加make GCCPREFIX=x86_64-elf-指定交叉编译工具。这时可以高兴的看到控制台闪烁,执行也很顺利。

执行

然后make qemu执行的过程也比较顺利。

image-20221003230427926

调试

首先,ARM 架构的Mac目前是不能使用gdb进行程序的调试的,默认的调试工具是lldb。然而经过查阅,对于交叉编译反而可以使用实验中对应的gdb工具:运行brew install i386-elf-gdb安装即可。

以调试lab1中的BIOS的执行为例。

下面的过程与指导书中“使用远程调试”部分类似。除此之外,额外将运行的汇编指令保存在q.log中。

在一个终端先执行:

shell
qemu-system-i386 -S -s -d in_asm -D bin/q.log -monitor stdio -hda bin/ucore.img

后在另一个终端执行:

shell
i386-elf-gdb

进入gdb调试界面。

shell
(gdb) file bin/kernel
Reading symbols from bin/kernel...
(gdb) target remote :1234
Remote debugging using :1234
0x0000fff0 in ?? ()

上述的过程相比原来makrfile中提供的make debug主要有两个好处:一是能够重定向到q.log方便进行对比;二是可以绕开make中的TERMINAL:=gnome-terminal(gnome-terminal仅在linux下可使用)

查看 CS:EIP 由于此时在实际模式下 CPU 在加电后执行的第一条指令的地址为 0xf000:0xfff0 => 0xffff0

shell
(gdb) x/i $cs
	0xf000:	add    %al,(%eax)
(gdb) x/i $eip
	0xfff0:	add    %al,(%eax)

再来看看这个地址的指令是什么

shell
(gdb) x/2i 0xffff0
   0xffff0:	ljmp   $0x3630,$0xf000e05b
   0xffff7:	das

可以看到 第一条指令执行完以后 会跳转到0xf000e05b也就是说 BIOS 开始的地址是 0xfe05b

打上断点

shell
(gdb) b *0x7c00
Breakpoint 1 at 0x7c00
(gdb) c
Continuing.

Breakpoint 1, 0x00007c00 in ?? ()

一开始为了方便后续在终端中配置了永久别名:

shell
alias makeq="make GCCPREFIX=x86_64-elf-"

当然更优雅的方法其实是修改make中的宏:

makefile
# try to infer the correct GCCPREFX
ifndef GCCPREFIX
# GCCPREFIX := $(shell if i386-elf-objdump -i 2>&1 | 
#...comment the original shell function
# 	echo "***" 1>&2; exit 1; fi)
GCCPREFIX := x86_64-elf-
endif

但是,由于makefile里默认认为调试工具一定叫gdb,且mac里没有gdb对应的command,因此这时候用永久别名是比较合适的。

shell
alias gdb="i386-elf-gdb"

这时候也可以修改make来达到自动化调试的目的:

makefile
WORKING_DIR=$(shell pwd)
debug: $(UCOREIMG)
	$(V)$(QEMU) -S -s -parallel stdio -hda $< -serial null &
	$(V)sleep 2
	$(V) osascript -e 'tell application "Terminal" to do script "cd $(WORKING_DIR); gdb -q -x tools/gdbinit"'

其中最后一句是为了产生一个在当前工作目录的新终端。

总结

前前后后也花了相当长的时间来应对环境的不同。后续的内容其实更吸引着我们去深入探索。

后续

已知问题: lab1 的chellenge无法正常切换user_mode,初步排查发现是出现了操作数异常,可能是%esp未正确赋值,但目前还没有找到方案。如果对此部分有较深研究,也欢迎交流。

image-20221130221829874
image-20221130221851517

chellenge以外的部分以及后两个实验均可正确得到结果。

image-20221130222030887

Ucore Lab0 on Apple Silicon Mac
http://lunaticsky-tql.github.io/posts/23191/
作者
Lunatic sky
发布于
2022年9月30日
许可协议