MIT 6.s081 实验解析——labs2

系列文章目录

MIT 6.s081 实验解析——labs1
MIT 6.s081 实验解析——labs2


文章目录

  • 系列文章目录
  • 测试判断流程
    • System call tracing
    • sysinfo![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ab9ca34f1fc64b6aa1df74613dc1a397.png)


测试判断流程

  1. 完成代码后将.c文件放入user文件夹中
  2. 在makefile文件的UPROGS处添加要测试的文件,如要添加的是sleep.c,则写为_sleep。
    在这里插入图片描述
  3. 重新编译xv6
make qemu
  1. 退出qemu,在文件夹下输入
./grade-lab-util <文件名>

//以sleep为例
./grade-lab-util sleep

System call tracing

在这里插入图片描述

trace 32 grep hello README

以上述指令来说,这个实验想要实现的效果是,跟踪grep hello README过程中所有的系统调用,其中32为掩码,是要跟踪的系统调用种类,将32变为2进制,根据下图,在要跟踪的系统调用位置置1。在这里插入图片描述
所以先更改kernel/proc.h的进程结构体,新增掩码:

    struct proc {
      ...
      int mask;
    };

为了实现进程间传递参数,需添加对mask的拷贝,在kernel/proc.c的fork定义中:

    int
    fork(void)
    {
      ...
      // Cause fork to return 0 in the child.
      np->trapframe->a0 = 0;
      np->mask = p->mask;
      ...
    }

接下来就是要去完成系统调用 trace 的函数定义,在该系统调用会接收用户态传递的参数,并将其赋值给mask,我们将定义写在kernel/sysproc.c中:

    uint64
    sys_trace(void){
      int n;
      argint(0,&n);//接收参数
      myproc()->mask = n;//赋给mask
      return 0;
    }

为了在syscall中能调用sys_trace,我们需要将其函数入口地址存入数组static uint64 (*syscalls[])(void)中,在其末尾加入[SYS_trace] sys_trace,即可。
最后我们要在syscall调用完系统调用后,通过本进程的mask来确认这个系统调用是不是被追踪的,若是则输出相关信息,为了方便信息输出,我们为其定义一个字符串数组,修改的文件为kernel/syscall.c:

    char *str[]={
    [SYS_fork]    "syscall fork",
    [SYS_exit]    "syscall exit",
    [SYS_wait]    "syscall wait",
    [SYS_pipe]    "syscall pipe",
    [SYS_read]    "syscall read",
    [SYS_kill]    "syscall kill",
    [SYS_exec]    "syscall exec",
    [SYS_fstat]   "syscall fstat",
    [SYS_chdir]   "syscall chdir",
    [SYS_dup]     "syscall dup",
    [SYS_getpid]  "syscall getpid",
    [SYS_sbrk]    "syscall sbrk",
    [SYS_sleep]   "syscall sleep",
    [SYS_uptime]  "syscall uptime",
    [SYS_open]    "syscall open",
    [SYS_write]   "syscall write",
    [SYS_mknod]   "syscall mknod",
    [SYS_unlink]  "syscall unlink",
    [SYS_link]    "syscall link",
    [SYS_mkdir]   "syscall mkdir",
    [SYS_close]   "syscall close",
    [SYS_trace]   "syscall trace",
    };
    void
    syscall(void)
    {
      int num;
      struct proc *p = myproc();

      num = p->trapframe->a7; //系统调用号
      if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
        // Use num to lookup the system call function for num, call it,
        // and store its return value in p->trapframe->a0
        p->trapframe->a0 = syscalls[num](); //系统调用的返回值
        if((p->mask >> num) & 1) //若该系统调用被跟踪
        	printf("%d: %s -> %d\n",p->pid,str[num],p->trapframe->a0);//输出信息
      } else {
        printf("%d %s: unknown sys call %d\n",
                p->pid, p->name, num);
        p->trapframe->a0 = -1;
      }
    }

描述一下整个系统调用的流程:核心点就在于可以通过usys.pl文件里对系统调用的定义,使得可以在用户空间调用系统调用。
在这里插入图片描述
在用户空间的trace.c定义了trace调用,然后通过ECALL指令触发向内核态的切换,将对应的系统调用号和参数存入寄存器,切换至内核态之后由syscall函数对调用进行响应,然后调用对应的系统调用。处理完成之后将结果返还给用户空间,再切换回用户态,完成一次系统调用。

sysinfo在这里插入图片描述

整体流程和trace差不多,获取非unused的进程数,核心就是遍历进程结构体数组proc,并判断其元素的state。

    uint64 get_used_proc(){
      struct proc *p;
      uint64 n = 0;
      for(p = proc; p < &proc[NPROC]; p++) {
        if(p->state != UNUSED) 
          n++;
      }
      return n;
    }

获取空闲内存,通过查看文件kernel/kalloc.c可知每个物理内存页的单位是PGSIZE=4096字节, 以一个单链表的形式管理空闲内存页,我们只需遍历该单链表获取空闲页数,每页计一个PGSIZE即可。

    uint64 get_free_memory(){
      uint64 n=0;
      struct run* r = kmem.freelist;
      while(r){
        r=r->next;
        n += PGSIZE;
      }
      return n;
    }

将这些信息填入sysinfo结构体,然后返还给用户空间。

    uint64 sys_sysinfo(){
      uint64 st;
      argaddr(0, &st);//获取从用户空间传入的指针。
      struct sysinfo p;//将信息存在结构体中
      p.nproc = get_used_proc();
      p.freemem = get_free_memory();
      if(copyout(myproc()->pagetable, st, (char *)&p, sizeof(p)) < 0)//拷贝回用户空间
        return -1;
      return 0;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/300636.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8S Prometheus-rocketmq-exporter配置

下载rocketmq-exporter 通过Docker仓库下载 docker pull sawyerlan/rocketmq-exporter:latest 然后打标签&#xff0c;推送到自己的仓库 也可通过代码自己build镜像 git clone GitHub - apache/rocketmq-exporter: Apache RocketMQ Prometheus Exporter 然后打标签&#x…

iPhone 恢复出厂设置后如何恢复数据

如果您在 iPhone 上执行了恢复出厂设置&#xff0c;您会发现所有旧数据都被清除了。这对于清理混乱和提高设备性能非常有用&#xff0c;但如果您忘记保存重要文件&#xff0c;那就是坏消息了。 恢复出厂设置后可以恢复数据吗&#xff1f;是的&#xff01;幸运的是&#xff0c;…

React Portals

简介 React Portal 可以将组件渲染到dom树的不同位置&#xff0c;同时可以渲染到任意父级元素&#xff0c;可以实现漂浮层功能。 使用样例 本篇文章通过React Portals实现对话框&#xff0c;下面将会给出具体实现。 protal组件 Portal.jsx import {useState} from "re…

Java环境准备:JDK与IDEA

新手小白学Java–环境准备篇 文章目录 新手小白学Java--环境准备篇第1节 JDK的下载与安装第2节 IDEA的下载与安装第3节 使用IDEA创建第一个Java项目第4节 使用小技巧查看电脑的操作系统版本显示出文件的后缀名IDEA 修改字体大小IDEA 修改显示主题色IDEA 修改单行注释的颜色IDEA…

Mysql SQL审核平台Yearning本地部署

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

Postman实现压力测试

从事软件开发对于压力测试并不陌生,常见的一些压测软件有Apache JMeter LoadRunner Gatling Tsung 等,这些都是一些比较专业的测试软件,对于我的工作来说一般情况下用不到这么专业的测试,有时候需要对一些接口进行压力测试又不想再安装新软件,那么可以使用Postman来实现对…

MyBatis入门源码一:配置解析

一、SqlSessionFactory 的构建&#xff1a;SqlSessionFactoryBuilder#build(…) 看一下我们mybatis-config.xml 配置的内容&#xff1a; parser.parse(): 解析配置文件 解析的内容很多&#xff0c;重点看解析数据源、解析mapper文件 build&#xff1a; 创建DefaultSqlSessi…

用队列实现栈oj题——225

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;LeetCode刷题|数据结构|Linux 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 题目要求&#xff1a;实现 MyStack 类&#xff1a;注意&#xff1a;示例&#xff1a;解释&#xff1a;提示&#xff1a; 解题核心数据结构的定义…

Redis概览

Redis存储是Key-Value结构的数据&#xff0c;其中Key是字符串类型&#xff0c;Value有5种常见的数据类型 字符串 String 哈希 hash 列表 list 集合 set 有序集合 sorted set / zset 各种数据类型的特性 字符串操作命令 : ● SET ke…

Go-gin-example 添加注释 第一部分 新建项目及api编写

文章目录 go-gin-example环境准备初始化 Go Modules基础使用 gin 安装测试gin是否引入 gin搭建Blog APIsgo-ini简述配置文件 阶段目标 编写简单API错误码包 完成一个demo初始化项目初始化项目数据库编写项目配置包拉取go-ini配置包在conf目录下新建app.ini文件&#xff0c;写入…

数据结构排序(一.基本概念、插入排序和希尔排序实现)

前段时间也是结束了二叉树的知识梳理&#xff08;大家想必满脑子都是递归了&#xff09;&#xff1a;二叉树链式结构的实现(二叉树的遍历以及各种常用功能函数的实现) 今天也要迈向全新的篇章了——排序。这次就先大概讲解一下排序&#xff0c;然后插入排序和希尔排序的介绍和实…

R304S 指纹识别模块功能实现示例

1 基本通信流程 1.1 UART 命令包的处理过程 1.2 UART 数据包的发送过程 UART 传输数据包前&#xff0c;首先要接收到传输数据包的指令包&#xff0c;做好传输准备后发送成功应答包&#xff0c;最后才开始传输数据包。数据包主要包括&#xff1a;包头、设备地址、包标识、包长…

Spring IOC的四种手动注入方法

手动注入 1.Set方法注入-五种类型的注入1.1 业务对象JavaBean第一步&#xff1a;创建dao包下的UserDao类第二步&#xff1a;属性字段提供set⽅法第三步&#xff1a;配置⽂件的bean标签设置property标签第四步&#xff1a;测试 1.2 常用对象String&#xff08;日期类型&#xff…

【AI视野·今日CV 计算机视觉论文速览 第282期】Wed, 3 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Wed, 3 Jan 2024 Totally 70 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Street Gaussians for Modeling Dynamic Urban Scenes Authors Yunzhi Yan, Haotong Lin, Chenxu Zhou, Weijie Wang, Haiya…

togaf 9.2中文版

尊敬的读者朋友们&#xff0c;本专栏为togaf 9.2 的个人学习笔记&#xff0c;我会尽量将信息完整地传递给大家&#xff0c;以便更多对 togaf 感兴趣的朋友不用花费巨资去购买相关资料。本文档不需要读者具备企业架构的预备知识。 专栏受众&#xff1a;企业架构师、业务架构师、…

Android WiFi 连接

Android WiFi 连接 1、设置中WiFi显示2、WiFi 连接流程2.1 获取PrimaryClientModeManager2.2 ClientModeImpl状态机ConnectableState2.3 ISupplicantStaNetworkCallback 回调监听 3、 简要时序图4、原生低层驱动5、关键日志 1、设置中WiFi显示 Android WiFi基础概览 packages/a…

阿里云服务器可用区是什么?

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

天津最新web前端培训班 如何提升web技能?

随着互联网的迅猛发展&#xff0c;web前端成为了一个热门的职业方向。越来越多的人希望能够通过学习web前端技术来提升自己的就业竞争力。为了满足市场的需求&#xff0c;许多培训机构纷纷推出了web前端培训课程。 什么是WEB前端 web前端就是web给用户展示的东西&#xff0c;…

DataFunSummit:2023年知识图谱在线峰会-核心PPT资料下载

一、峰会简介 AIGC&#xff0c;ChatGPT以及发布的GPT-4相信已经给大家带来足够的冲击&#xff0c;那么对于知识图谱的应用产生哪些变化和变革&#xff1f;知识图谱在其中如何发挥作用呢&#xff1f;通过LLM是否有可能辅助创建通用大规模知识图谱&#xff1f;AIGC时代下行业知识…

http缓存

http缓存 header里缓存相关的属性 Expires 响应头,代表该资源的过期时间&#xff0c;在http1.0引入Cache-control 请求/响应头&#xff0c;可以配置缓存策略&#xff0c;在http1.1引入&#xff0c;与Expires同时存在时&#xff0c;优先使用Cache-controlIf-Modified-Since …