xv6 lab2

发布时间:2026/11/7 20:34:25

xv6 lab2 仅作个人学习记录本章讲系统调用隔离启动过程实验准备了解系统调用流程阅读user.husy.splsyscall.hsyscall.csysproc.ctrace.c首先来看user.h保存着所用的系统调用函数和用户态的库函数struct stat; // 文件状态结构体存储文件大小、类型、权限、inode等元信息 struct rtcdate; // 实时时钟日期结构体存储年/月/日/时/分/秒时间信息 // 系统调用声明内核提供用户程序通过syscall触发 // 创建子进程返回值父进程返回子进程PID子进程返回0失败返回-1 int fork(void); // 终止当前进程noreturn标记表示该函数不会返回 int exit(int status) __attribute__((noreturn)); // 阻塞等待任意子进程退出将子进程退出状态存入传入指针返回退出子进程PID int wait(int* wstatus); // 创建管道参数int* fd为长度2的数组fd[0]读端文件描述符fd[1]写端成功返回0 int pipe(int* fd); // 文件写系统调用fd文件描述符buf写入数据缓冲区n写入字节数返回实际写入字节数 int write(int fd, const void* buf, int n); // 文件读系统调用fd文件描述符buf存储读出数据n期望读取字节数返回实际读取字节数 int read(int fd, void* buf, int n); // 关闭指定文件描述符fd释放进程占用的文件资源成功返回0 int close(int fd); // 向PID为pid的进程发送终止信号成功返回0失败返回-1 int kill(int pid); // 加载并执行ELF可执行文件 // path可执行文件路径argv命令行参数数组char*数组末尾以NULL结尾 int exec(char* path, char** argv); // 打开文件path文件路径flags打开标志(读/写/创建等)返回文件描述符 int open(const char* path, int flags); // 创建特殊设备节点文件path节点路径mode文件权限类型dev设备主次设备号 int mknod(const char* path, short mode, short dev); // 删除文件硬链接若链接计数为1则直接删除文件本体 int unlink(const char* path); // 获取fd对应文件的元数据存入stat结构体指针输出参数 int fstat(int fd, struct stat* stat_buf); // 创建文件硬链接oldpath原文件路径newpath新链接路径 int link(const char* oldpath, const char* newpath); // 创建目录path为目录路径 int mkdir(const char* path); // 修改当前进程工作目录至path指定路径 int chdir(const char* path); // 复制文件描述符fd返回新的文件描述符指向同一文件资源 int dup(int fd); // 获取当前进程PID返回进程ID整数值 int getpid(void); // 堆内存扩容函数传入增量字节数返回扩容前堆结束地址用于实现malloc底层 char* sbrk(int increment); // 阻塞进程sleep指定秒数 int sleep(int seconds); // 获取系统开机运行总时长返回开机到现在的秒数 int uptime(void); // ulib.c 用户层标准工具库函数封装系统调用/字符串内存操作 // 获取文件元数据path文件路径stat_buf输出文件状态信息 int stat(const char* path, struct stat* stat_buf); // 字符串拷贝将src字符串完整复制到dest缓冲区不做边界检查 char* strcpy(char* dest, const char* src); // 内存区域拷贝支持源与目标内存重叠场景count为拷贝字节数 void *memmove(void* dest, const void* src, int count); // 在字符串s中查找第一个字符c返回对应字符指针无匹配返回NULL char* strchr(const char* s, char c); // 字符串比较s1s2返回正数s1s2返回0s1s2返回负数 int strcmp(const char* s1, const char* s2); // 格式化输出至指定文件描述符fdfmt格式化字符串可变参数 void fprintf(int fd, const char* fmt, ...); // 格式化输出到标准输出(控制台)fmt格式化字符串可变参数 void printf(const char* fmt, ...); // 从标准输入读取一行字符串存入bufmax限制最大读取长度返回buf指针 char* gets(char* buf, int max); // 计算字符串s长度不含末尾\0返回字节长度 uint strlen(const char* s); // 将内存区域首地址dest的count字节全部填充为value值 void* memset(void* dest, int value, uint count); // 用户态堆内存分配分配size字节内存返回分配内存首地址 void* malloc(uint size); // 释放malloc分配的ptr堆内存 void free(void* ptr); // 将数字字符串s转换为对应十进制整型数字返回 int atoi(const char* s); // 内存内容比较前count字节逐字节对比相同返回0不同返回差值 int memcmp(const void *s1, const void *s2, uint count); // 内存拷贝不支持源与目标内存重叠count拷贝字节数 void *memcpy(void *dest, const void *src, uint count);有一个特别的函数int exec(char*, char**); 他的第二个参数是字符串指针数组char **argv char *argv[];字符串指针数组拆开两层理解char *单个字符串指针比如argv[0]存程序名字符串首地址char **指向一堆char*的指针也就是指针数组。exec()会遍历所有参数、拷贝到用户进程栈中再看usus.pl这个文件是一个Perl 脚本它的核心作用是自动生成一个汇编文件通常命名为usys.S这个汇编文件包含了系统调用的“存根Stubs”代码封装ecall陷入指令。#!/usr/bin/perl -w # Generate usys.S, the stubs for system calls. print # Generated by usys.pl - do not edit\n; print #include \kernel/syscall.h\\n sub entry {} my $name shift; print .global $name\n; print ${name}:\n; print li a7, SYS_${name}\n; print ecall\n; print ret\n; } entry(fork); entry(exit); entry(wait); entry(pipe); entry(read); entry(write); entry(close); entry(kill); entry(exec); entry(open); entry(mknod); entry(unlink); entry(fstat); entry(link); entry(mkdir); entry(chdir); entry(dup); entry(getpid); entry(sbrk); entry(sleep); entry(uptime); entry(trace); //添加的先来了解一下在系统调用时RISC-V的a0-a7寄存器寄存器用途a0/a1进入内核时前两个参数内核返回用户态系统调用返回值a2~a6第 3~7 个系统调用参数a7系统调用号专用寄存器在Makefile中usys.S会和用户态程序一起链接为可执行程序usys.pl运行时会拼接调用函数.global fork fork: li a7, SYS_fork会去syscall.h中索引 ecall ret 返回值放在a0a0-a1(如果返回俩个参数)ecall是特权指令触发陷阱陷入内核完成用户态到内核态切换系统调用当在用户态程序中调用read(1bufsizeof(buf)) 程序不能直接执行内核代码。它必须通过一种特殊的机制中断/异常切换到内核态。1、调用的时候会在usys.S中把文件拼接好调用号放在a7中执行ecall特权指令进入内核态此时 CPU 会把所有用户寄存器保存到p-trapframe陷阱帧内核态不能直接访问用户态的虚拟内存2、切到内核态后 进入trap.c的usertrap(), 异常原因会存在 scause 寄存器 用户态陷入ecall是编号8 由它判断是什么中断异常发现是ecall然后调用syscall()scause 值异常类型8User-mode ecall用户态执行 ecall系统调用9Supervisor-mode ecall内核态 ecall1,2,5 等缺页、非法指令、外设中断等其它异常3、执行syscall.c从头文件中找到SYS_read然后通过 copyin 拷贝一份用户态对应调用的虚拟地址读取陷阱帧中的寄存器拿到参数。之后跳转到对应的内核函数执行执行结束返回参数放到a0返回trap() 内核sret切回用户态usys.S代码retC 代码拿到 a0 里的返回值.任务一trace目标添加一个名为trace的新系统调用它可以控制内核记录并打印当前进程执行了哪些指定的系统调用。核心需求控制机制trace系统调用接收一个整数mask掩码作为参数通过比特位按位或来指定追踪哪些系统调用。例如系统调用号SYS_fork的值是 1用户代码调用trace(1 SYS_fork)就表示只追踪fork。传入的掩码转为二进制看那位是1就说明我要追踪哪一个系统调用掩码是32位4字节整数系统调用有21个足够了。打印格式当被追踪的进程执行了 mask 中指定的系统调用时内核必须在该系统调用即将返回时打印一行信息。格式进程ID: syscall 系统调用名称 - 返回值例如输出3: syscall read - 1023不需要打印系统调用的传入参数。继承特性如果一个进程启用了trace那么它此后通过fork()创建的所有子进程都必须自动继承该追踪掩码。也就是说fork()的子进程要拿到父进程的掩码参数隔离特性追踪功能不能影响系统中其他未开启trace的独立进程。实现路径关键点跑通整个系统调用注册流程修改你提到的user/usys.pl、user/user.h、kernel/syscall.h。修改kernel/proc.h中的进程控制块struct proc增加一个变量来保存掩码。修改kernel/proc.c中的fork()将父进程的掩码值赋给子进程。修改kernel/syscall.c中的syscall()函数所有系统调用的统一内核分发器在这里拦截系统调用完成后的时刻判断掩码并打印信息。看一下用户态的trace.c#include kernel/param.h #include kernel/types.h #include kernel/stat.h #include user/user.h int main(int argc, char *argv[]) { int i; char *nargv[MAXARG]; if(argc 3 || (argv[1][0] 0 || argv[1][0] 9)){ fprintf(2, Usage: %s mask command\n, argv[0]); exit(1); } if (trace(atoi(argv[1])) 0) { fprintf(2, %s: trace failed\n, argv[0]); exit(1); } for(i 2; i argc i MAXARG; i){ nargv[i-2] argv[i]; } exec(nargv[0], nargv); exit(0); }先检测传入参数是否合规字符串本质是字符数组如果argv[1] 142那么argv[1][0] 1 , argv[1][1] 4 ,为了检测第二个参数是不是字符。然后传入参数调用trace() 去内核中运行。usys.pl中添加trace系统调用proc.h头文件proc() 结构体中加入trace_mask参数在pro.c的fork函数中加入传参在syspro.c中添加trace在syscall.h头文件中添加掩码在syscall.c中添加打印的字符串并且做比对user.h头文件中添加系统调用函数最后运行结果
延伸阅读

更多相关文章

2026/11/6 11:10:13

Go语言Context核心机制与最佳实践详解

1. Go语言Context深度解析在Go语言开发中,Context是一个极其重要但又容易被误解的概念。作为Go标准库的一部分,context包提供了一种优雅的方式来管理请求生命周期、传递请求范围的值以及处理取消信号。理解Context的运作机制,是写出健壮、高效…

2026/11/4 20:44:18

机器人组装延时摄影全流程:从策划到后期制作详解

1. 项目概述:当机器人遇见定格动画如果你对机器人、机械工程或者创意视频制作中的任何一个领域感兴趣,那么“Cassie Assembly Time-lapse”这个项目标题,绝对能让你眼前一亮。它描述的,正是将一台名为Cassie的双足机器人从零散的零…

2026/11/7 20:30:10

电工证分分几种类别的,全国通用的怎么考最靠谱

电工证分分几种类别的,全国通用的怎么考最靠谱 你是不是也在为“电工证分分几种类别的”这个问题发愁?在网上一搜,信息太多又太乱,不知道哪个靠谱,怕被中介骗钱、浪费时间。别急,今天我就用从业10年经验,给你讲讲电工证到底是怎么分的、全国通用的怎…

2026/11/7 20:30:10

电工证 几年一审合格标准与通过率

电工证几年一审2026河南最新政策解读:怕考不过白交培训费? 怕考不过白交培训费?2026年河南最新政策明确,电工证几年一审、复审流程、考试标准全在这里,别再被培训机构忽悠! 电工证几年一审?2026河南最新政策怎么说?…

2026/11/7 20:30:10

荆门考电工证在哪学保姆级教程:工地太忙根本没时间复习考试

荆门考电工证在哪学保姆级教程:工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,这是许多在荆门从事建筑行业的电工朋友的真实写照。尤其是像许昌的在职建筑工人,每天工作时间长、任务重,抽不出时间准备电工证考试,这让很多工友感到焦虑。别急,…

2026/11/7 20:30:10

电工证几月份可以报名千万别踩坑

电工证几月份可以报名千万别踩坑 实操考试心里没底怕挂科,尤其是像你这样刚毕业的周口应届生,面对电工证报名时间、考试流程和内容一无所知,很容易在报考过程中踩坑。别急,下面我从报名时间、考试内容、证书价值、备考建议等方面,帮你理清思路,避免走弯…

2026/11/7 20:25:09

你学历不高怕报不上名?红河蒙自高压电工证网上查询流程全解析

你学历不高怕报不上名?红河蒙自高压电工证网上查询流程全解析 你学历不高怕报不上名?其实红河蒙自高压电工证报考门槛没你想象的那么高,关键是你得知道怎么网上查询和准备资料。今天我就从商丘转岗从业者角度,把红河蒙自高压电工证的整个流程讲明白,让你…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/7 0:03:08

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科

郑州报考避坑指南:电工证和钳工证怎么选?实操考试心里没底怕挂科 实操考试心里没底怕挂科?你不是一个人。特别是在郑州这样的城市,很多施工企业负责人和一线作业人员在报考电工证和钳工证时都面临着同样的困惑。到底该考哪个证?哪个更适合自己?哪个证书…

2026/11/7 0:03:08

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱?

广西电工证办理流程全解析:外省证怎么转?在哪考最靠谱? 之前考的证在外省能不能转过来?这个问题我遇到太多了,今天就拿广西电工证办理流程来具体说说,别再走弯路了。广西电工证的报考、复审、继续教育这些环节,如果你不了解,真的会吃大亏,尤其对于从…

2026/11/7 0:03:08

电气电工证都有哪些保姆级教程

电气电工证都有哪些保姆级教程 你是不是正愁不知道去哪报名,怕被中介坑?别急,这篇保姆级教程专为河南初次报考人员准备,帮你搞清楚 电气电工证都有哪些 ,以及如何避开那些坑。 电气电工证都有哪些?别被五花八门的证书搞懵了…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑