网站黑名单查询,小米3g 架设wordpress,企业网站的建设流程包括,怎么建立一个简易的网站大家好#xff0c;我叫徐锦桐#xff0c;个人博客地址为www.xujintong.com#xff0c;github地址为https://github.com/xjintong。平时记录一下学习计算机过程中获取的知识#xff0c;还有日常折腾的经验#xff0c;欢迎大家访问。 Lab2就是了解一下xv6的系统调用流程我叫徐锦桐个人博客地址为www.xujintong.comgithub地址为https://github.com/xjintong。平时记录一下学习计算机过程中获取的知识还有日常折腾的经验欢迎大家访问。 Lab2就是了解一下xv6的系统调用流程熟悉一下系统调用过程中的结构啥的。
一、xv6系统调用流程
以trace系统调用为例
1、在用户态的user.h中加入对应加入对应系统调用的跳板函数 2、在user/usys.pl中加入对应的entry() 这个entry()是从用户态到内核态的一个关键它的宏定义展开代码为
entry的具体宏展开是:
sub entry {my $name shift;print .global $name\n;print ${name}:\n;print li a7, SYS_${name}\n;print ecall\n;print ret\n;
}# 经过compiler后, entry(trace)为我们在usys.S里生成了如下的汇编代码# usys.S
.global trace
trace:li a7, SYS_traceecallret通过上述代码可以看出来entry将对应系统调用的调用号(SYS_trace)加入到a7寄存器中然后通过ecallrisc-v汇编的系统调用指令从用户态进入内核态。
3、之后首先会跳到kernel/syscall.c中的syscall函数。
系统调用号SYS_trace–就是个宏定义从a7寄存器中获取然后通过这个号调用对应的系统调用函数返回值存在a0寄存器中。 4、通过系统调用号找到对应的系统调用函数
static uint64 (*syscalls[])(void) {
[SYS_fork] sys_fork,
[SYS_exit] sys_exit,
[SYS_wait] sys_wait,
[SYS_pipe] sys_pipe,
[SYS_read] sys_read,
[SYS_kill] sys_kill,
[SYS_exec] sys_exec,
[SYS_fstat] sys_fstat,
[SYS_chdir] sys_chdir,
[SYS_dup] sys_dup,
[SYS_getpid] sys_getpid,
[SYS_sbrk] sys_sbrk,
[SYS_sleep] sys_sleep,
[SYS_uptime] sys_uptime,
[SYS_open] sys_open,
[SYS_write] sys_write,
[SYS_mknod] sys_mknod,
[SYS_unlink] sys_unlink,
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
[SYS_trace] sys_trace,
[SYS_sysinfo] sys_sysinfo,
};其实就是个数组每个数组存着对应的系统调用函数指针。像SYS_fork、SYS_exit这些其实就是一个宏定义定义的编号具体源码如下
// System call numbers
#define SYS_fork 1
#define SYS_exit 2
#define SYS_wait 3
#define SYS_pipe 4
#define SYS_read 5
#define SYS_kill 6
#define SYS_exec 7
#define SYS_fstat 8
#define SYS_chdir 9
#define SYS_dup 10
#define SYS_getpid 11
#define SYS_sbrk 12
#define SYS_sleep 13
#define SYS_uptime 14
#define SYS_open 15
#define SYS_write 16
#define SYS_mknod 17
#define SYS_unlink 18
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
#define SYS_trace 22
#define SYS_sysinfo 23具体的系统调用的函数实现放在了各个文件中这里是个extern函数。
比如说sys_trace放在kernel/sysproc.c文件中sys_read放在kernel/sysfile.c文件中。 二、将内核态数据复制到用户态
应为内核态和用户态是隔离的它俩拥有不用的地址空间、寄存器。所以获取系统调用用户态传入的参数我们需要argint()、argaddr、argstr进行获取。这三个函数在kernel/syscall.c文件中
将内核态的数据返回到用户态这里是用到了copyout函数。具体源码如下
// Copy from kernel to user.
// Copy len bytes from src to virtual address dstva in a given page table.
// Return 0 on success, -1 on error.
/*将 len 个字节从 src 复制到给定页表中的虚拟地址 dstva
*/
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{uint64 n, va0, pa0;while(len 0){va0 PGROUNDDOWN(dstva); // 找到虚拟地址对应的虚拟页表起始地址pa0 walkaddr(pagetable, va0); // 通过虚拟页表找到对应的物理页表起始地址if(pa0 0)return -1;n PGSIZE - (dstva - va0); // 计算该页表的剩余空间// 如果剩余空间大于要拷贝的数据长度只拷贝数据长度部分if(n len)n len;/*在物理页表中以(void *)(pa0 (dstva - va0))地址开始将n个字节的src复制到对应位置*/memmove((void *)(pa0 (dstva - va0)), src, n); len - n;src n;dstva va0 PGSIZE;}return 0;
}核心就是通过虚拟地址找到对应变量的物理地址然后直接复制到的物理地址上面。
流程 1、找到虚拟地址对应的虚拟页表起始地址。 2、通过虚拟页表找到对应的物理页表起始地址 3、如果剩余空间大于要拷贝的数据长度只拷贝数据长度部分 4、在物理页表中以(void *)(pa0 (dstva - va0))地址开始将n个字节的src复制到对应位置
三、杂
内核态的头文件
内核态的函数声明都在kernel/defs.h头文件中。 一些结构
kernel/proc.c中定义了一个
struct proc proc[NPROC];存着当前所有进程的proc结构。 每个进程都对应一个proc结构该结构存储着该进程的信息运行状态进程名字pid号等等。