lab4:以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34

目录

安装编译工具链

制作根文件系统

编译linux内核

启动qemu

启动linux内核

调试准备

启动调试 


环境:ubuntu-18.04.6

安装编译工具链

 这里需要注意的是,由于我们是arm64内核,因此需要用gdb-multiarch来进行调试


   
   
  1. sudo apt install gcc-aarch64-linux-gnu
  2. sudo apt install libncurses5-dev build-essential git bison flex libssl-dev
  3. sudo apt install gdb-multiarch

制作根文件系统

linux的启动需要配合根文件系统,这里我们利用busybox来制作一个简单的根文件系统


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

打开静态库编译选项


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

 指定编译工具


   
   
  1. export ARCH=arm64
  2. export CROSS_COMPILE=aarch64-linux-gnu-

编译


   
   
  1. make
  2. make install

编译完成,在busybox目录下生成_install目录

制作文件系统


   
   
  1. cd _install
  2. mkdir etc dev lib

etc

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


   
   
  1. cd etc
  2. code profile
  3. #!/bin/sh
  4. export HOSTNAME=imingz
  5. export USER=root
  6. export HOME=/home
  7. export PS1= "[$USER@$HOSTNAME \W]\# "
  8. PATH=/bin:/sbin:/usr/bin:/usr/sbin
  9. LD_LIBRARY_PATH=/lib:/usr/lib: $LD_LIBRARY_PATH
  10. export PATH LD_LIBRARY_PATH
  11. code inittab
  12. ::sysinit:/etc/init.d/rcS
  13. ::respawn:-/bin/sh
  14. ::askfirst:-/bin/sh
  15. ::ctrlaltdel:/bin/umount -a -r
  16. code fstab
  17. #device mount-point type options dump fsck order
  18. proc /proc proc defaults 0 0
  19. tmpfs /tmp tmpfs defaults 0 0
  20. sysfs /sys sysfs defaults 0 0
  21. tmpfs /dev tmpfs defaults 0 0
  22. debugfs /sys/kernel/debug debugfs defaults 0 0
  23. kmod_mount /mnt 9p trans=virtio 0 0
  24. mkdir -p init.d
  25. code init.d/rcS
  26. mkdir -p /sys
  27. mkdir -p /tmp
  28. mkdir -p /proc
  29. mkdir -p /mnt
  30. /bin/mount -a
  31. mkdir -p /dev/pts
  32. mount -t devpts devpts /dev/pts
  33. echo /sbin/mdev > /proc/sys/kernel/hotplug
  34. mdev -s

dev

sudo mknod console c 5 1
   
   

lib

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

   
   

编译linux内核


   
   
  1. make defconfig ARCH=arm64
  2. 将下面的配置加入.config文件下面
  3. code .config
  4. CONFIG_DEBUG_INFO=y
  5. CONFIG_INITRAMFS_SOURCE= "./root"
  6. CONFIG_INITRAMFS_ROOT_UID=0
  7. CONFIG_INITRAMFS_ROOT_GID=0
  8. 将之前制作好的根文件系统 cp到root目录下
  9. cp -r ../busybox-1.33.1/_install root
  10. sudo mknod root/dev/console c 5 1

执行编译

make ARCH=arm64 Image -j8  CROSS_COMPILE=aarch64-linux-gnu-
   
   

启动qemu


   
   
  1. 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
  2. wget https://download.qemu.org/qemu-4.2.1.tar.xz
  3. tar xvJf qemu-4.2.1.tar.xz
  4. cd qemu-4.2.1
  5. ./configure --target-list=x86_64-softmmu,x86_64-linux-user,arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --enable-kvm
  6. make
  7. sudo make install

启动linux内核

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

   
   

成功启动linux后

调试准备

使用gettimeofday库函数


   
   
  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <sys/time.h>
  4. int main()
  5. {
  6. time_t tt;
  7. struct timeval tv;
  8. struct tm *t;
  9. #if 0
  10. gettimeofday(&tv, NULL);
  11. #else
  12. asm volatile(
  13. "add x0, x29, 16\n\t" //X0寄存器用于传递参数&tv
  14. "mov x1, #0x0\n\t" //X1寄存器用于传递参数NULL
  15. "mov x8, #0xa9\n\t" //使用X8传递系统调用号169
  16. "svc #0x0\n\t" //触发系统调用
  17. );
  18. #endif
  19. tt = tv.tv_sec; //tv是保存获取时间结果的结构体
  20. t = localtime(&tt); //将世纪秒转换成对应的年月日时分秒
  21. printf( "time: %d/%d/%d %d:%d:%d\n",
  22. t->tm_year + 1900,
  23. t->tm_mon,
  24. t->tm_mday,
  25. t->tm_hour,
  26. t->tm_min,
  27. t->tm_sec);
  28. return 0;
  29. }

把test.c进行交叉编译,需要静态编译,动态链接库找不到 time 的系统调用,只能找到函数

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

把test放到root文件夹下,重新编译后就可查看到test文件

make ARCH=arm64 Image -j8  CROSS_COMPILE=aarch64-linux-gnu-
   
   

 使用vscode调试需要在.vscode配置launch.json 和 tasks.json


   
   
  1. {
  2. // launch.json
  3. // Use IntelliSense to learn about possible attributes.
  4. // Hover to view descriptions of existing attributes.
  5. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  6. "version": "0.2.0",
  7. "configurations": [
  8. {
  9. "name": "(gdb) linux",
  10. "type": "cppdbg",
  11. "request": "launch",
  12. "preLaunchTask": "vm",
  13. "program": "${workspaceRoot}/vmlinux",
  14. "miDebuggerPath": "/usr/bin/gdb-multiarch",
  15. "miDebuggerServerAddress": "localhost:1234",
  16. "args": [],
  17. "stopAtEntry": true,
  18. "cwd": "${workspaceFolder}",
  19. "environment": [],
  20. "externalConsole": false,
  21. "MIMode": "gdb",
  22. "miDebuggerArgs": "-n",
  23. "targetArchitecture": "x64",
  24. "setupCommands": [
  25. {
  26. "text": "dir .",
  27. "ignoreFailures": false
  28. },
  29. {
  30. "text": "add-auto-load-safe-path ./",
  31. "ignoreFailures": false
  32. },
  33. {
  34. "text": "-enable-pretty-printing",
  35. "ignoreFailures": true
  36. }
  37. ]
  38. }
  39. ]
  40. }

   
   
  1. {
  2. // tasks.json
  3. // See https://go.microsoft.com/fwlink/?LinkId=733558
  4. // for the documentation about the tasks.json format
  5. "version": "2.0.0",
  6. "tasks": [
  7. {
  8. "label": "vm",
  9. "type": "shell",
  10. "command": "qemu-system-aarch64 -m 128M -smp 1 -cpu cortex-a57 -machine virt -kernel arch/arm64/boot/Image -initrd ../rootfs-arm.cpio.gz -append \"rdinit=/init console=ttyAMA0 loglevel=8\" -nographic -s",
  11. "presentation": {
  12. "echo": true,
  13. "clear": true,
  14. "group": "vm"
  15. },
  16. "isBackground": true,
  17. "problemMatcher": [
  18. {
  19. "pattern": [
  20. {
  21. "regexp": ".",
  22. "file": 1,
  23. "location": 2,
  24. "message": 3
  25. }
  26. ],
  27. "background": {
  28. "activeOnStart": true,
  29. "beginsPattern": ".",
  30. "endsPattern": ".",
  31. }
  32. }
  33. ]
  34. },
  35. {
  36. "label": "build linux",
  37. "type": "shell",
  38. "command": "make",
  39. "group": {
  40. "kind": "build",
  41. "isDefault": true
  42. },
  43. "presentation": {
  44. "echo": false,
  45. "group": "build"
  46. }
  47. }
  48. ]
  49. }

启动调试 

在窗口左下角的断点设置处新增断点 __arm64_sys_gettimeofday

启动linux内核,按下F5进行调试

执行./test 

 可以看到调用栈如下

 

 

 

 

        在Linux系统中系统调用发生时,CPU会把当前程序指针寄存器PC放入ELR_EL1寄存器里,把PSTATE放入SPSR_EL1寄存器里,同时Linux系统从用户态切换到内核态(从EL0切换到EL1),这时SP指的是SP_EL1寄存器,用户态堆栈的栈顶地址依然保存在SP_EL0寄存器中。也就是说异常(这里是指系统调用)发生时CPU的关键状态sp、pc和pstate分别保存在SP_EL0、ELR_EL1和SPSR_EL1寄存器中。

        el0_sync在完成保存现场的工作之后,会根据ESR_EL1寄存器确定同步异常产生的原因(svc指令触发了系统调用),所以排在最前面的就是条件判断跳转到el0_svc,el0_svc中主要负责调用C代码的el0_svc_handler处理系统调用和ret_to_user系统调用返回。

        从系统调用返回前会处理一些工作(work_pending),比如处理信号、判断是否需要进程调度等,ret_to_user的最后是kernel_exit 0负责恢复现场,与保存现场kernel_entry 0相对应,kernel_exit 0的最后会执行eret指令系统调用返回。eret指令所做的工作与svc指令相对应,eret指令会将ELR_EL1寄存器里值恢复到程序指针寄存器PC中,把SPSR_EL1寄存器里的值恢复到PSTATE处理器状态中,同时会从内核态转换到用户态,在用户态堆栈栈顶指针sp代表的是sp_el0寄存器。

      

       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在FreeRTOS系统中,由于FreeRTOS是一个嵌入式实时操作系统,它并不直接支持Linux的gettimeofday函数。但是,你可以通过以下步骤在FreeRTOS中使用类似的功能: 1. 首先,在FreeRTOS中创建一个新的任务或者添加到现有任务中。该任务将负责获取时间信息。 2. 在任务中包含头文件 `<sys/time.h>`,这样可以访问到gettimeofday函数的声明。 3. 在任务中调用gettimeofday函数来获取时间信息。 下面是一个示例代码来演示如何在FreeRTOS中使用类似于gettimeofday函数的功能: ```c #include <sys/time.h> void getTimeOfDayTask(void *pvParameters) { struct timeval tv; while (1) { // 获取时间信息 gettimeofday(&tv, NULL); // 在这里处理时间信息,例如输出到串口或者执行其他操作 // ... // 休眠一段时间,例如100ms vTaskDelay(pdMS_TO_TICKS(100)); } } int main() { // 创建一个任务来获取时间信息 xTaskCreate(getTimeOfDayTask, "getTimeOfDayTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); // 启动FreeRTOS调度器 vTaskStartScheduler(); // 如果一切正常,永远不会执行到这里 return 0; } ``` 在这个示例中,我们创建了一个名为`getTimeOfDayTask`的任务来获取时间信息。在任务中,我们使用`gettimeofday`函数来获取时间信息,并在任务中处理这些信息。任务使用`vTaskDelay`函数来休眠一段时间,以模拟定期获取时间信息的功能。 请注意,由于FreeRTOS是一个实时操作系统,任务的优先级和调度可能会影响时间信息的获取精度。在实际应用中,请根据需要进行适当的配置和调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值