Lab3 【哈工大_操作系统】系统调用

news2024/10/3 2:42:51

本节将更新哈工大《操作系统》课程第三个 Lab 实验 系统调用。按照实验书要求,介绍了非常详细的实验操作流程,并提供了超级无敌详细的代码注释。文末附完整标准答案代码,包括系统调用实现 who.c 和测试函数 iam.cwhoami.c 以及超详细注释。

实验目的:

  • 建立对系统调用接口的深入认识;
  • 掌握系统调用的基本过程;
  • 能完成系统调用的全面控制;
  • 为后续实验做准备。

实验任务:

在 Linux 0.11 上添加两个系统调用,并编写两个简单的应用程序测试它们。
1、第一个系统调用是 iam(),完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来。要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为EINVAL。
2、第二个系统调用是 whoami(),它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中,同时确保不会对 name 越界访存(name 的大小由 size 说明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。
3、运行添加过新系统调用的 Linux 0.11,在其环境下编写两个测试程序 iam.c 和 whoami.c。

实验工具准备:

文件名介绍
hit-操作系统实验指导书.pdf哈工大OS实验指导书
Linux内核完全注释(修正版v3.0).pdf赵博士对Linux v0.11 OS进行了详细全面的注释和说明
file1615.pdfBIOS 涉及的中断数据手册
hit-oslab-linux-20110823.tar.gzhit-oslab 实验环境
gcc-3.4-ubuntu.tar.gzLinux v0.11 所使用的编译器
Bochs 汇编级调试指令bochs 基本调试指令大全
最全ASCII码对照表0-255屏幕输出字符对照的 ASCII 码
x86_64 常用寄存器大全x86_64 常用寄存器大全

一、应用程序如何调用系统调用

1、创建实验工程 oslab_Lab2

  • 解压 hit-oslab-linux-20110823.tar.gz ,并命名为 os_lab_Lab2 ,在此源码基础上我们进一步完成实验。
  • 编译及运行:
cd ~/my_space/OS_HIT/oslab_Lab2/linux-0.11/    // 工程文件夹
make all                                       // 编译
../run                                         // 启动 Bochs

2、创建 NR_whoami 和 NR_iam 两个宏

==注意:==此时不是修改内核目录里的,而是修改在 v0.11 的开发环境里的这个文件。(这步很多同学会犯错,导致后续在 linux-v0.11 环境下使用 gcc 编译测试函数时报错找不到这两个宏)

具体原因:可以参照《Linux内核完全注释(修正版v3.0).pdf》

在这里插入图片描述

  • 挂载 linux-v0.11 的磁盘,并在 include/unistd.h 中添加宏
cd oulab_Lab2
sudo ./mount-hdc
cd hdc/usr/include
gedit unistd.h
  • 通过文本编辑器,在 unistd.h 头文件中手动添加宏
#define __NR_iam        72
#define __NR_whoami        73

二、从“int 0x80”进入内核函数

用户程序调用进入内核的步骤

  1. init/main.c 内核初始化时,调用量 sched_init() 初始化函数
  2. kernel/sched.c 中定义sched_init: void sched_init(void) { // …… set_system_gate(0x80,&system_call); }
  3. include/asm/system.h 定义宏 set_system_gate :#define set_system_gate(n,addr) _set_gate(&idt[n],15,3,addr)
  4. include/asm/system.h 定义宏 _ set_gate :填写IDT(中断描述符表),将 system_call 函数地址写到 0x80 对应的中断描述符中,也就是在中断 0x80 发生后,自动调用函数 system_call。

1、修改 kernel/system_call.s 文件中的系统调用总数

// 由原来的 72 修改为 74
nr_system_calls = 74

2、在 include/linux/sys.h 文件中增加 whoami() 和 iam() 两个函数声明

extern int sys_whoami();
extern int sys_iam();
fn_ptr sys_call_table[] = { sys_setup,sys_exit, sys_fork, sys_read,..., sys_iam, sys_whoami }    // 表中添加的函数顺序必须和 _NR_xxxxxx 的值对应

三、实现 sys_iam() 和 sys_whoami()

我需要编写系统调用函数来实现这两个功能。值得注意的是,每个系统调用都有一个 sys_xxxxxx() 与之对应,它们都是我们学习和模仿的好对象。

  • 此处的要点是如何实现:在用户态和核心态之间传递数据。其难点是:指针参数传递的是应用程序所在地址空间的逻辑地址,在内核中如果直接访问这个地址,访问到的是内核空间中的数据,不会是用户空间的。

open 为例:

lib/open.c:
	- 系统调用是用 eax、ebx、ecx、edx 寄存器来传递参数的
	- 获取用户地址空间(用户数据段)中的数据依靠的就是段寄存器 fs,下面该转到 sys_open 执行了
fs/open.c:
	- 将参数传给了 open_namei()
	- open_namei( ) 用 ==get_fs_byte()== 获得一个字节的用户空间中的数据

所以说,在whoami() 中实现用户态和和心态之间的数据传递,即通过:put_fs_xxx() 和 get_fs_xxx() 都是用户空间和内核空间之间的桥梁

  • oslab_Lab2/linux-0.11/kernel/ 文件夹下创建系统调用实现 who.c。具体代码如下:(已有详细注释,此处将不再赘述)
// sys_iam 和 sys_whoami 系统调用函数

#include <string.h>
#include <errno.h>
#include <asm/segment.h>

// 内核中存放name,23字符 + '\0' = 24
char msg[24];

// 将字符串参数 name 拷贝到内核中保存下来
// return:拷贝的字符数。如果name的字符个数超过了23,则返回“­-1”,并置errno为EINVAL。
int sys_iam(const char* name) 
{
    int i;
    char tmp[30];   // 临时存储,操作失败不影响 msg
    
    // 从用户态内存获取数据,存入 tmp
    for(i = 0; i < 30; i++) {
        tmp[i] = get_fs_byte(name+i);
        if(tmp[i] == '\0')
            break;
    }
    // printk(tmp);

    i = 0;
    // 计算 name 的长度
    while(tmp[i] != '\0' && i < 30) {
        i++;
    }
    int len = i;
    // 长度大于 23 返回报错
    if(len > 23) {
        return -(EINVAL);
    }
    strcpy(msg, tmp);

    return i;
}

// 将由 iam() 保存的名字拷贝到 name 指向的用户地址空间,size 指定 name 的大小
// return:如果size小于需要的空间,则返回“­-1”,并置errno为 EINVAL
int sys_whoami(char* name, unsigned int size)
{     
    int len = 0;
    // 计算长度
    for(; msg[len] != '\0'; len++);
    // 长度大于则返回
    if(len > size) {
        return -(EINVAL);
    }
    // 从内核态获取数据,存入 name
    int i = 0;
    for(; i < size; i++) {
        put_fs_byte(msg[i], name+i);
        if(msg[i] == '\0') 
            break;
    }
    return i;
}

值得注意的是,在编写代码过程中,我们可以通过 printk() 函数在屏幕上输出数据来进行调试,适当地向屏幕输出一些程序运行状态的信息,也是一种很高效、便捷的调试方法。

四、修改编译规则 Makefile

我们需要为新建的 who.c 文件添加编译规则来创建编译对象以及添加响应的依赖,后续即可使用 make all 一键编译。

  • 修改 oslab_Lab2/linux-0.11/kernel/Makefile 文件,修改如下:
OBJS  = sched.o system_call.o traps.o asm.o fork.o \
    panic.o printk.o vsprintf.o sys.o exit.o \
    signal.o mktime.o who.o

### Dependencies:
who.s who.o:  who.c ../include/linux/kernel.h ../include/unistd.h

五、编写测试函数

编写两个测试函数,来测试我们编写的系统调用函数 sys_iam() 和 sys_whoami。

  1. iam.c:将字符串参数 name 的内容拷贝到内核中保存下来
  2. whoami.c:将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中并显示。
  • 值得说明的是,我们编写后的两个测试函数需要在 linux-v0.11 环境下进行编译。由于 linux-v0.11 作为一个很小的操作系统,只有编译工具 vi ,使用起来非常不方便。因此,我们可以直接在 ubuntu 环境下进行编写,再通过挂载 hdc 磁盘来将这两个文件拷贝到 linux-v0.11 系统下,然后编译、运行

1、在 oslab_Lab2/linux-0.11/kernel 文件夹下创建两个测试函数

  • iam.c
#include <errno.h>
#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>

_syscall1(int, iam, const char*, name);

int main(int argc,char ** argv)
{
    iam(argv[1]);
    return 0;
}
  • whoami.c
#define __LIBRARY__
#include <unistd.h>

_syscall2(int, whoami, char*, name, unsigned int, size);

int main(int argc, char* agrv[])
{
    char s[30];
    whoami(s, 30);
    printf("%s\n", s);
    
    return 0;
}

2、将两个测试函数移动到 linux-v0.11 系统下

通过挂载 hdc 磁盘,将编写的两个测试函数移动到 linux-v0.11 系统下,以便下一步进行编译。由于我们每在 ubuntu 系统下修改一次测试函数都要将其移动到 linux-v0.11 系统下进行编译,为了方便,我们可以编写一个 bash 脚本,存放如下命令。

cd ~/my_space/OS_HIT/oslab_Lab2
touch cp.sh                                     // 创建脚本

脚本内容如下:

sudo ./mount-hdc                                // 挂载磁盘
sudo cp ./linux-0.11/kernel/iam.c ./hdc/iam.c          // 将 iam.c 移动到 hdc 磁盘
sudo cp ./linux-0.11/kernel/whoami.c ./hdc/whoami.c    // 将 whoami.c 移动到 hdc 磁盘
sudo umount hdc                                 // 卸载
./run                                           // 启动 linux-v0.11

3、编译与运行

在编译之前,尤其注意,上述创建的 iam.c 和 whoami.c 两个文件中不能含有任何 // 之类的注释,否则在使用 linux-v0.11 系统进行编译时会报错。

  • 在 linux-v0.11 系统下,我们运行如下命令回到根目录,可以看到移动过来的 iam.cwhoami.c 文件。
cd ../..
ls

  • 编译,运行如下指令,可以生成 iamwhoami 两个可执行文件。
gcc -o iam iam.c -Wall           // 编译 iam.c 文件
gcc -o whoami whoami.c -Wall     // 编译 whoami.c 文件
// -Wall 是 GCC 的一个选项,用来开启所有警告
  • 运行,分别运行两个文件,得到如下所示结果
./iam Joker      // 将 Joker 存入内核
./whoami         // 从内核中取出 ./iam 存入的字符并显示

在这里插入图片描述

至此,Lab3 实验介绍完毕。


也许有人觉得比较实验步骤比较多比较复杂,特此总结一下每个步骤:

  1. hdc/usr/include/unistd.h 中添加系统调用号 __NR_iam__NR_whoami
  2. kernel/system_call.s 修改系统调用总数 nr_system_calls = 74
  3. include/linux/sys.h 添加函数声明 extern int sys_whoami();extern int sys_iam();
  4. 创建两个函数的实现:/kernel/who.c
  5. kernel/Makefile 中添加编译规则
  6. /kernel 中创建测试函数 iam.c 和 whoami.c
  7. 编写 bash 脚本,将测试函数移到 linux-v0.11 下
  8. 在 Linux-v0.11 下编译 iam.c 和 whoami.c

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mac M2安装单机版 MongoDB 7.x

1. 通过tgz包安装MongoDB 1.1 下载并解压缩安装包 官网下载 mac OS 的 MongoDB 安装包&#xff0c;这里选择7.x版本进行安装&#xff08;下载链接&#xff09; 下载好的tgz包&#xff0c;双击解压缩&#xff0c;并重命名为mongdb 将安装包拷贝到安装目录&#xff0c;笔者的…

深入解析开源大模型的GPU资源需求与优化策略

随着大模型的火热很多项目中都使用到了开源大模型&#xff0c;这时候准确评估大模型的GPU资源非常重要&#xff0c;主要有下面几个方面 成本效率&#xff1a;GPU是昂贵的资源。高估内存需求可能导致在硬件上的不必要支出&#xff0c;而低估则可能导致系统故障或性能下降。 性…

【数据结构】什么是红黑树(Red Black Tree)?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;红黑树的概念 &#x1f4cc;红黑树的操作 &#x1f38f;红黑树的插入操作 &#x1f38f;红黑树的删除操作 结语 &#x1f4cc;红黑树的概念 我们之前学过了…

资源《Arduino 扩展板3-WS2812》说明。

资源链接&#xff1a; Arduino 扩展板3-WS2812 1.文件明细&#xff1a; 2.文件内容说明 包含&#xff1a;AD工程、原理图、PCB。 3.内容展示 4.简述 该文件为PCB工程&#xff0c;采用AD做的。 该文件打板后配合Arduino使用&#xff0c;属于Arduino的扩展板。 该文件主要…

通义千问“百宝箱”:效率神器,解放你的双手!

你在为播客转文字、音视频转写和长文本阅读而烦恼吗&#xff1f;今天&#xff0c;就让通义千问的“百宝箱”来帮你解决这些难题&#xff01; 最近&#xff0c;我发现通义千问首页隐藏着一个效率神器——“百宝箱”&#xff08;现在更名为工具箱&#xff09;&#xff0c;简直是…

batch和momentum

&#x1f680; 机器学习系列前期回顾 1、初识机器学习 2、线性模型到神经网络 3、local minima的问题如何解决 &#x1f680;在初识机器学习中&#xff0c;了解了机器学习是如何工作的并引入了线性模型&#xff0c;在线性模型到神经网络这节&#xff0c;将线性模型进一步改进为…

FireRedTTS - 小红书最新开源AI语音克隆合成系统 免训练一键音频克隆 本地一键整合包下载

小红书技术团队FireRed最近推出了一款名为FireRedTTS的先进语音合成系统&#xff0c;该系统能够基于少量参考音频快速模仿任意音色和说话风格&#xff0c;实现独特的音频内容创造。 FireRedTTS 只需要给定文本和几秒钟参考音频&#xff0c;无需训练&#xff0c;就可模仿任意音色…

【Golang】关于Go语言字符串转换strconv

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

ProtoBuf快速上手

文章目录 创建 .proto文件编译 .proto文件编译后生成的文件序列化与反序列化的使用 此篇文章实现内容&#xff1a; 对一个通讯录的联系人信息&#xff0c;使用PB进行序列化&#xff0c;并将结果输出对序列化的内容使用PB进行反序列化&#xff0c;解析联系人信息并输出联系人信…

【成神之路】Ambari实战-015-代码生命周期-metainfo-category详解

1.Redis 集群 metainfo.xml 示例 <?xml version"1.0"?> <metainfo><schemaVersion>2.0</schemaVersion><services><service><!-- Redis 集群服务的基本信息 --><name>REDIS</name><displayName>Redi…

MongoDB的安装与增删改查基本操作

MongoDB是一种非关系型数据库&#xff0c;是NoSQL语言&#xff0c;但是又是最接近关系型数据库的。内部存储不是表结构&#xff0c;但是可以对数据进行表结构的操作。 一、安装 在官网&#xff1a;Download MongoDB Community Server | MongoDB下载系统对应的版本进行安装即可…

html+css+js实现Collapse 折叠面板

实现效果&#xff1a; HTML部分 <div class"collapse"><ul><li><div class"header"><h4>一致性 Consistency</h4><span class"iconfont icon-jiantou"></span></div><div class"…

UFS 3.1架构简介

整个UFS协议栈可以分为三层:应用层(UFS Application Layer(UAP)),传输层(UFS Transport Layer(UTP)),链路层(UIC InterConnect Layer(UIC))。应用层发出SCSI命令(UFS没有自己的命令使用的是简化的SCSI命令),在传输层将SCSI分装为UPIU,再经过链路层将命令发送给Devices。下…

通信工程学习:什么是TCP传输控制协议

TCP&#xff1a;传输控制协议 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是因特网协议套件中最重要的协议之一&#xff0c;它为应用程序提供了可靠、面向连接的通信服务。以下是TCP协议的详细解释&#xff1a; 一、TCP传输控制协议的…

双十一有哪些值得入手的好物?这五款宝藏好物不容错过!

在这个金秋送爽、收获满满的季节里&#xff0c;我们迎来了万众瞩目的双十一购物狂欢节。这不仅仅是一场简单的消费盛宴&#xff0c;更是每一位消费者期待已久、精心筹备的年度购物盛典。随着电商平台的不断革新与优惠力度的持续加码&#xff0c;双十一已经从一个简单的促销日成…

使用百度文心智能体创建多风格表情包设计助手

文章目录 一、智能定制&#xff0c;个性飞扬二、多元风格&#xff0c;创意无限 百度文心智能体平台为你开启。百度文心智能体平台&#xff0c;创建属于自己的智能体应用。百度文心智能体平台是百度旗下的智能AI平台&#xff0c;集成了先进的自然语言处理技术和人工智能技术&…

单目3d重建DUSt3R 笔记

目录 DUSt3R 三维重建 报错RecursionError: maximum recursion depth exceeded in comparison 报错 numpy.core.multiarray failed to import 报错Numpy is not available 解决 升级版mast3r 速度变慢 修改了参数设置脚本&#xff1a; 测试效果 操作技巧 DUSt3R 三维重…

[已解决] Install PyTorch 报错 —— OpenOccupancy 配环境

目录 关于 常见的初始化报错 环境推荐 torch, torchvision & torchaudio cudatoolkit 本地pip安装方法 关于 OpenOccupancy: 语义占用感知对于自动驾驶至关重要&#xff0c;因为自动驾驶汽车需要对3D城市结构进行细粒度感知。然而&#xff0c;现有的相关基准在城市场…

torchvision.transforms.Resize()的用法

今天我在使用torchvision.transforms.Resize()的时候发现&#xff0c;一般Resize中放的是size或者是(size,size)这样的二元数。 这两个里面&#xff0c;torchvision.transforms.Resize((size,size))&#xff0c;大家都很清楚&#xff0c;会将图像的h和w大小都变成size。 但是…

【python实操】python小程序之过七游戏以及单词单复数分类

引言 python小程序之过7游戏、单词单复数分类 文章目录 引言一、过7游戏1.1 题目1.2 代码1.2.1 while循环1.2.2 for循环1.2.3 调用函数形式 1.3 代码解释 二、单词单复数分类2.1 题目2.2 代码2.3 代码解释 三、思考3.1 过七游戏3.2 单词单复数分类 一、过7游戏 1.1 题目 7的倍…