操作系统实验1(BOCHS、自编译 Linux 内核、自定义 syscall)

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 配置文件 bochsrsromimagevgaromimage 目录自行查找

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 应当从 PKGBUILDvalidpgpkeys 中获取

gpg --recv-keys --keyserver hkps://keys.openpgp.org/ ABAF11C65A2970B130ABE3C479BE3E4300411886 647F28654894E3BD457199BE38DBBDC86092693E A2FF3A36AAA56654109064AB19802F8B0D70FC30 C7E7849466FE2358343588377258734B41C31549

修改内核源码(Task 3)

如果不进行该任务,可以跳过这一步。

参考资料:

Patching packages (简体中文) - ArchWiki

diff(1) — Arch manual pages

获取源码但不进行构建

makepkg --nobuild

进入 src 目录,将 archlinux-linux 复制为两份相同的目录,重命名为 package.origpackage.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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人生的意义在于偷懒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值