Linux操作系统分析 实验四

配置ARM64环境

安装编译工具链

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev  build-essential git bison flex libssl-dev

制作根文件系统

wget  https://busybox.net/downloads/busybox-1.33.1.tar.bz2
tar -xjf busybox-1.33.1.tar.bz2
cd busybox-1.33.1

menuconfig中选择静态编译

make menuconfig
Settings --->
 [*] Build static binary (no shared libs) 

指定编译工具

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

编译

make
make install

制作内存根镜像
根目录添加etc、dev和lib目录

cd _install
mkdir etc dev lib

结果

$ ls
bin  dev  etc  lib  linuxrc  sbin  usr

在etc分别创建profile、inittab、fstab、init.d/rcS 文件

cd etc
touch profile
vim profile
touch inittab
vim inittab
touch fstab
vim fstab

profile

export HOSTNAME=bryant
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

inittab

::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

fstab

proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0

init.d下的rcS文件
命令

mkdir init.d
cd init.d
touch rcS
vim rcS
chmod 777 rcS

rcS

mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

制作dev和lib目录中的内容

cd ../../dev
sudo mknod console c 5 1
cd ../lib
cp /usr/aarch64-linux-gnu/lib/*.so*  -a .

lib
拷贝lib库,支持动态编译的应用程序运行:

cp /usr/aarch64-linux-gnu/lib/*.so*  -a .

编译内核

用之前的linux内核源码可以,根据 arch/arm64/configs/defconfig 文件生成 .config

cd ~/linux_lab/lab4/linux-5.4.34
make defconfig ARCH=arm64

将下面的配置加入.config文件下面

CONFIG_DEBUG_INFO=y  //设置CONFIG_DEBUG_INFO方便调试
CONFIG_INITRAMFS_SOURCE="./root" //指定 kernel ramdisk 的位置, ramdisk j将直接被编译到 kernel 镜像中
CONFIG_INITRAMFS_ROOT_UID=0
CONFIG_INITRAMFS_ROOT_GID=0

将之前制作好的根文件系统cp到root目录下

cp -r ../busybox-1.33.1/_install root
sudo mknod root/dev/console c 5 1

编译

sudo cp -r ../busybox-1.33.1/_install root
make ARCH=arm64 Image -j8  CROSS_COMPILE=aarch64-linux-gnu-

启动qemu

下载qemu

cd ..
apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip python-capstone virtualenv
wget https://download.qemu.org/qemu-4.2.1.tar.xz
tar xvJf qemu-4.2.1.tar.xz
cd qemu-4.2.1
./configure --target-list=x86_64-softmmu,x86_64-linux-user,arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --enable-kvm
make 
sudo make install

启动linux内核

/usr/local/bin/qemu-system-aarch64 -m 512M -smp 4 -cpu cortex-a57 -machine virt -kernel ~/linux_lab/lab4/linux-5.4.34/arch/arm64/boot/Image -append "rdinit=/linuxrc nokaslr console=ttyAMA0 loglevel=8" -nographic -s

触发系统调用

编写test函数触发系统调用

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
 
int main()
{
      time_t tt;
      struct timeval tv;
      struct tm *t;
#if 0
      gettimeofday(&tv,NULL);
#else
      asm volatile(
          "add   x0, x29, 16\n\t"  //X0寄存器用于传递参数&tv
          "mov   x1, #0x0\n\t"     //X1寄存器用于传递参数NULL
          "mov   x8, #0xa9\n\t"   //使用X8传递系统调用号169
          "svc   #0x0\n\t"            //触发系统调用
      );
#endif
      tt = tv.tv_sec;                    //tv是保存获取时间结果的结构体
      t = localtime(&tt);                //将世纪秒转换成对应的年月日时分秒
      printf("time: %d/%d/%d %d:%d:%d\n",
             t->tm_year + 1900,
             t->tm_mon,
             t->tm_mday,
             t->tm_hour,
             t->tm_min,
             t->tm_sec);
      return 0;
}

交叉编译

aarch64-linux-gnu-gcc -o test test.c -static

修改vscode的tasks.json和launch.json文件
在vscode中打断点

 

启动调试,然后在终端执行test.c,程序停在了断点处



堆栈的调用情况

 

用户态程序执行svc指令,CPU会把当前程序指针寄存器PC放入ELR_EL1寄存器里,把PSTATE放入SPSR_EL1寄存器里,把异常产生的原因(这里是调用了svc指令触发系统调用)放在ESR_EL1寄存器里。这时CPU是知道异常类型和异常向量表的起始地址的,所以可以自动把VBAR_EL1寄存器的值(vectors),和第3组Synchronous的偏移量0x400相加,即vectors + 0x400,得出该异常向量空间的入口地址,然后跳转到那里执行异常向量空间里面的指令。每个异常向量空间仅有128个字节,最多可以存储32条指令(每条指令4字节),而且异常向量空间最后一条指令是b指令,对于系统调用来说会跳转到el0_sync,这样就从异常向量空间跳转同步异常处理程序的入口。

el0_sync代码如下

el0_sync通过kernel_entry 0从用户态进入内核态,完成上下文切换,保护现场。之后el0_sync根据寄存器esr_el1来判断同步异常产生的原因。svc指令触发了系统调用,所以排在最前面的就是条件判断跳转到el0_svc,el0_svc中主要负责调用C代码的el0_svc_handler处理系统调用和ret_to_user系统调用返回。el0_svc通过bl指令跳转到了el0_svc_handler,在el0_svc_handler又跳转到了el0_svc_common函数接着执行。

invoke_syscall函数将通用寄存器中的内容传入syscall_fn(),引出系统调用内核处理函数 __arm64_sys_gettimeofday。之后invoke_syscall会将系统调用后的返回值放入x0寄存器中,最后通过ret_to_user函数返回用户态。

ret_to_user的最后是kernel_exit 0负责恢复现场,与保存现场kernel_entry 0相对应

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值