Operating System Experiment 1
实验环境:Arch Linux (x86_64)
内核版本:5.17.5
实验说明见 PDF
Task 1
用 NASM 编写 MBR 引导程序,在 BOCHS 虚拟机中测试
安装 bochs 与 nasm
sudo pacman -S bochs nasm
编写 boot.asm
并编译
org 07c00h
mov ax, cs
mov ds, ax
mov es, ax
call DispStr
jmp $
DispStr:
mov ax, BootMessage
mov bp, ax
mov cx, 16
mov ax, 01301h
mov bx, 000ch
mov dl, 0
int 10h
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0
dw 0xaa55
nasm boot.asm -o boot.bins
创建镜像文件
bximage
如下操作
========================================================================
bximage
Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
$Id: bximage.cc 14091 2021-01-30 17:37:42Z sshwarts $
========================================================================
1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info
0. Quit
Please choose one [0] 1
Create image
Do you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd
Choose the size of floppy disk image to create.
Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M.
[1.44M]
What should be the name of the image?
[a.img]
Creating floppy image 'a.img' with 2880 sectors
The following line should appear in your bochsrc:
floppya: image="a.img", status=inserted
将程序加载到镜像文件
dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
编写 bochs 配置文件 bochsrs
,romimage
和 vgaromimage
目录自行查找
megs:32
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
floppya : 1_44=a.img, status=inserted
boot : floppy
log : bochsout.txt
mouse : enabled=0
使用配置启动 bochs
bochs -f bochsrc
========================================================================
Bochs x86 Emulator 2.7
Built from SVN snapshot on August 1, 2021
Timestamp: Sun Aug 1 10:07:00 CEST 2021
========================================================================
00000000000i[ ] BXSHARE not set. using compile time default '/usr/share/bochs'
00000000000i[ ] reading configuration from bochsrc
------------------------------
Bochs Configuration: Main Menu
------------------------------
This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate. Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found. When you are satisfied with the configuration, go
ahead and start the simulation.
You can also start bochs with the -q option to skip these menus.
1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now
Please choose one: [6] 6
00000000000i[ ] installing x module as the Bochs GUI
00000000000i[ ] using log file bochsout.txt
Next at t=0
(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b ; ea5be000f0
<bochs:1> b 0x7c00
<bochs:2> c
(0) Breakpoint 1, 0x0000000000007c00 in ?? ()
Next at t=14034560
(0) [0x000000007c00] 0000:7c00 (unk. ctxt): mov ax, cs ; 8cc8
<bochs:3> n
Next at t=14034561
(0) [0x000000007c02] 0000:7c02 (unk. ctxt): mov ds, ax ; 8ed8
<bochs:4> n
Next at t=14034562
(0) [0x000000007c04] 0000:7c04 (unk. ctxt): mov es, ax ; 8ec0
<bochs:5> n
Next at t=14034563
(0) [0x000000007c06] 0000:7c06 (unk. ctxt): call .+2 (0x00007c0b) ; e80200
<bochs:6> n
Next at t=14041965
(0) [0x000000007c09] 0000:7c09 (unk. ctxt): jmp .-2 (0x00007c09) ; ebfe
<bochs:7>
依次输入直至窗口出现 Hello, OS world!
字样
b 0x7c00
c
n
n
n
...
Task 2 & Task 3
自行编译 Linux 内核,并添加自定义 syscall
此处本人使用 Arch Linux 的 Arch Build System,与传统方法有较大出入
参照资料:
Adding a New System Call — The Linux Kernel documentation
Kernel (简体中文)/Arch Build System (简体中文) - ArchWiki
安装必要包
sudo pacman -S base-devel asp pacman-contrib
按照 Arch Wiki 操作
cd ~/
mkdir build
cd build/
asp update linux
asp export linux
修改 PKGBUILD
(重要)
修改包名,使新内核与当前内核共存。
如果不进行修改,编译出的内核将替换当前系统内核,造成不可预知的后果
pkgbase=linux-custom
避免创建文档:删去 make htmldocs
与 "$pkgbase-docs"
< make htmldocs
< pkgname=("$pkgbase" "$pkgbase-headers" "$pkgbase-docs")
---
> pkgname=("$pkgbase" "$pkgbase-headers")
修改 prepare()
,添加或取消注释以下行,使其使用前一版本内核的配置
make oldconfig # using old config from previous kernel version
make prepare
启用并行编译,在 prepare()
前加入,根据你的 CPU 修改数字
export MAKEFLAGS="-j18"
生成新校验和
updpkgsums
你可能需要从 keyserver 接受密钥,这里的 keyid 应当从 PKGBUILD
的 validpgpkeys
中获取
gpg --recv-keys --keyserver hkps://keys.openpgp.org/ ABAF11C65A2970B130ABE3C479BE3E4300411886 647F28654894E3BD457199BE38DBBDC86092693E A2FF3A36AAA56654109064AB19802F8B0D70FC30 C7E7849466FE2358343588377258734B41C31549
修改内核源码(Task 3)
如果不进行该任务,可以跳过这一步。
参考资料:
Patching packages (简体中文) - ArchWiki
获取源码但不进行构建
makepkg --nobuild
进入 src
目录,将 archlinux-linux
复制为两份相同的目录,重命名为 package.orig
和 package.new
。
在 package.new
中做的修改会与 package.orig
做比较,生成一个补丁文件,接下来需要将补丁文件应用到构建过程中。
以下修改均在 package.new
中进行,请检查两目录是否一致,否则重新进行目录复制
在 /include/linux/syscalls.h
添加定义
asmlinkage long sys_add(long a, long b);
asmlinkage long sys_max(long a, long b, long c);
在 /include/uapi/asm-generic/unistd.h
添加宏定义,修改 syscall 总数
#define __NR_xyzzy 451
__SYSCALL(__NR_add, sys_add)
#define __NR_xyzzy 452
__SYSCALL(__NR_max, sys_max)
#define __NR_syscalls 453
在 /kernel/sys_ni.c
添加 fallback
COND_SYSCALL(add);
COND_SYSCALL(max);
在 /arch/x86/entry/syscalls/syscall_64.tbl
添加新入口
451 common add sys_add
452 common max sys_max
在 /kernel/sys.c
中添加宏定义,并实现自定义 syscall 的逻辑
注意此处宏定义的参数数量及参数写法
SYSCALL_DEFINE2(add, long, a, long, b)
{
return __sys_add(a,b);
}
SYSCALL_DEFINE3(max, long, a, long, b, long, c)
{
return __sys_max(a,b,c)
}
long __sys_add(long a,long b)
{
return a+b;
}
long __sys_max(long a,long b,long c)
{
return a>b?(a>c?a:c):(b>c?b:c);
}
根据我们做出的修改创建补丁文件
diff --unified --recursive -N --text package.orig package.new > package.patch
检查 package.patch
内容,若无误则将其复制到上一级目录,即 linux/
。
继续修改 PKGBUILD
,在 source
数组中添加 package.patch
,更新校验和
updpkgsums
开始编译
耐心等待,16 线程全开编译约 20 分钟
makepkg -s
如果编译中途失败,在修改完成后可以添加 -e
参数进行增量编译,无需重新编译,节省时间。
编译完成后安装
sudo pacman -U linux-custom-5.17.5.arch1-1-x86_64.pkg.tar.zst linux-custom-headers-5.17.5.arch1-1-x86_64.pkg.tar.zst
如果使用 grub,可以执行以下命令自动生成新的配置文件(假设配置文件是 /boot/grub/grub.cfg
):
sudo grub-mkconfig -o /boot/grub/grub.cfg
测试新 syscall
重启,在 grub 中进入我们的新内核 linux-custom
。
图形化界面应该不会正常启动,使用 Ctrl+Alt+F2 切换到 tty,在命令行中进行测试。
在 vim 中编写测试代码 test.c
:
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
long a, b, c;
scanf("%ld%ld%ld", &a, &b, &c);
long ret = syscall(451, a, b);
long ret2 = syscall(452, a, b, c);
printf("%ld+%ld=%ld\n", a, b, ret);
printf("The biggest number in %ld, %ld and %ld is %ld", a, b, c, ret2);
return 0;
}
gcc test.c -o test
./test
Task 4
在给定目录下为所有 txt 文件添加用户名及时间信息,要求可以实现时间信息格式化,若已存在时间信息则更新而非追加。
path=$1
format=$2
if [ $# -gt 0 ]; then
for file in $path/*.txt; do
tag=$(tail -n 1 "$file")
if [[ "$tag" == *"$USER"* ]]; then
echo "Time info exists in "$file", update it."
sed -i '$ d' "$file"
fi
if [ $# -gt 1 ]; then
echo $USER: $(date +"$format") >>$file
else
echo $USER: $(date) >>$file
fi
done
else
echo "Argument invalid!"
fi
添加执行权限
chmod +700 os_exp1_task4.sh