华中科技大学操作系统实验课 实验四

2023-11-08

一、实验目的

  • (1)理解设备是文件的概念。
  • (2)掌握Linux模块、驱动的概念和编程流程
  • (3)Windows /Linux下掌握文件读写基本操作

二、实验内容

  • (1)编写一个Linux内核模块,并完成模块的安装/卸载等操作。
  • (2)编写Linux驱动程序(字符类型或杂项类型)并编程应用程序测试。
    功能:write几个整数进去,read出其和或差或最大值。
  • (3)编写Linux驱动程序(字符类型或杂项类型)并编程应用程序测试。
    功能:有序读和写内核缓冲区,可以重复读,可以覆盖写。返回实际读写
    字节数。
  • (4)Linux中文件软连接和硬链接的验证实验

三、实验要求

  • 寝室提前做完,老师机房检查和答疑。1和4必做,2和3选择其一

四、实验过程

任务一 编写一个Linux内核模块,并完成模块的安装/卸载等操作。

借鉴blog:(二)Linux设备驱动的模块化编程

1.编写模块

test1.c

    #include <linux/kernel.h>
    #include <linux/module.h>
    
    static int hello_init(void)
    {
        printk("hello_init");
    
        return 0;
    }
    
    static void hello_exit(void)
    {
        printk("hello_exit");
    }
    
    
    MODULE_LICENSE("GPL");
    module_init(hello_init);
    module_exit(hello_exit);

2. 编写Makefile文件

#————————————————
#版权声明:本文为CSDN博主「hanp_linux」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
#原文链接:https://blog.csdn.net/hanp_linux/article/details/90445164

#定义一些变量,增加代码的阅读性和扩展性
#`uname -r`这种写法就是执行uname -r这个shell命令,从而构造这个绝对路径,
#因为每个人的计算机的绝对路径都不一样,这样提高通用性,
#对于我的主机,这个路径相当于/lib/modules/4.4.0-31-generic/build
KERNEL_PATH := /lib/modules/`uname -r`/build
PWD := $(shell pwd)

#这个名字表示:要生产的模块的名字,最终会生成hello.ko //这里改为test1(你自己的.c文件名)
MODULE_NAME := test1
   
#表示要生成hello.ko要依靠中间文件hello.o  kbuild系统会将源码hello.c编译成hello.o
obj-m := $(MODULE_NAME).o
   
#当执行make命令默认会寻找第一个目标,即all
all:
	$(MAKE) -C $(KERNEL_PATH) M=$(PWD)
   
#执行make clean要执行的操作,将编译生成的中间文件删掉
clean:
	rm -rf .*.cmd *.o *.mod.c *.order *.symvers  *.ko

3. 编译

在当前文件夹下打开终端

make

在这里插入图片描述

4. 安装模块

sudo insmod test1.ko

一些查看操作

dmesg //查看系统从开机到当前时刻由printk输出到缓存的所有log
sudo dmesg -c //查看显示log信息,并将整个缓存清除掉
sudo dmesg -C //不显示log信息,将整个缓存清除掉
lsmod | grep test1//查看是否有test1这个模块

输入

 sudo insmod test1.ko
 sudo dmesg -c 

输出
在这里插入图片描述
很奇怪为什么会输出hello_exit 应该是hello_init,别人的没问题,但我的有。

5. 卸载模块

卸载并打印内存输出

sudo rmmod test1.ko
sudo dmesg -c 

在这里插入图片描述

任务二 编写Linux驱动程序(字符类型或杂项类型)并编程应用程序测试

借鉴自:(三)写一个完整的Linux驱动程序访问硬件并写应用程序进行测试

1.编写驱动程序代码

要求:
输入为两个整形数据字符型指针,int num[2]。
输出为一个整形字符型指针,int sum[1].

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

dev_t devno;
int major = 255;
const char DEVNAME[] = "hello_device";
char data[64]  = "";
char data2[64] = "";

int hello_open(struct inode * ip, struct file * fp)
{
    printk("%s : %d\n", __func__, __LINE__);
    
    /* 一般用来做初始化设备的操作 */
    return 0;
}

int hello_close(struct inode * ip, struct file * fp)
{
    printk("%s : %d\n", __func__, __LINE__);
    
    /* 一般用来做和open相反的操作,open申请资源,close释放资源 */
    return 0;
}

ssize_t hello_read(struct file * fp, char __user * buf, size_t count, loff_t * loff)
{
    int ret;
    
    int *datan = (int*)data;
    int *data2n = (int*)data2;
    data2n[0] = datan[0]+datan[1];
    /* 将用户需要的数据从内核空间copy到用户空间(buf) */
    printk("%s : %d\n", __func__, __LINE__);
    if ((ret = copy_to_user(buf, data2, count)))
    {
        printk("copy_to_user err\n");
        return -1;
    }
    return count;
}

ssize_t hello_write(struct file * fp, const char __user * buf, size_t count, loff_t * loff)
{
    int ret;
    /* 将用户需要的数据从内核空间copy到用户空间(buf) */
    printk("%s : %d\n", __func__, __LINE__);
    if ((ret = copy_from_user(data, buf, count)))
    {
        printk("copy_from_user err\n");
        return -1;
    }
    return count;
}

/* 2. 分配file_operations结构体 */
struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open  = hello_open,
    .release = hello_close,
    .read = hello_read,
    .write = hello_write
};
struct cdev cdev;

static int hello_init(void)
{
    int ret;
    printk("%s : %d\n", __func__, __LINE__);
    
    /* 1. 生成并注册设备号 */
    devno = MKDEV(major, 0);
    ret  = register_chrdev_region(devno, 1, DEVNAME);
    if (ret != 0)
    {
        printk("%s : %d fail to register_chrdev_region\n", __func__, __LINE__);
        return -1;
    }
    
    /* 3. 分配、设置、注册cdev结构体 */
    cdev.owner = THIS_MODULE;
    ret = cdev_add(&cdev, devno, 1);
    cdev_init(&cdev, &hello_fops);
    if (ret < 0)
    {
        printk("%s : %d fail to cdev_add\n", __func__, __LINE__);
        return -1;
    }
    printk("success!\n");
    return 0;
}

static void hello_exit(void)
{
    printk("%s : %d\n", __func__, __LINE__);
      
    /* 释放资源 */
    cdev_del(&cdev);
    unregister_chrdev_region(devno, 1);
}

MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

2. 编写Makefile文件

KERNEL_PATH := /lib/modules/`uname -r`/build
PWD := $(shell pwd)
MODULE_NAME := hello

obj-m := $(MODULE_NAME).o

all:
	$(MAKE) -C $(KERNEL_PATH) M=$(PWD)

clean:
	rm -rf .*.cmd *.o *.mod.c *.order *.symvers *.tmp *.ko

3.编写app应用文件测试驱动程序

输入为int num[2]。
输出打印在终端上。
代码中num[2]为123,2。

app.c

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>

int main(char argc, char * argv[])
{
    int fd;
    int ret;
    char buf[64] = "hello";
    char buf2[64] = "";
    int num[2]={123,2};
    char* num2 = (char*)num;
    
    /* 将要打开的文件的路径通过main函数的参数传入 */
    if (argc != 2)
    {
        printf("Usage: %s <filename>\n", argv[0]);
        return -1;
    }
    
    fd = open(argv[1], O_RDWR);
    if (fd < 0)
    {
        perror("fail to open file");
        return -1;
    }
    
    /* write data */
    ret = write(fd, num2, sizeof(num));
    if (ret < 0)
    {
        printf("read err!");
        return -1;
    }

    /* read data */
    ret = read(fd, num2, sizeof(num));
    if (ret < 0)
    {
        printf("read err!");
        return -1;
    }
    printf("buf2 = %d\n", num[0]);
    
    
    
    close(fd);
    return 0;
}

4.编译&安装&链接模块

make
sudo insmod hello.ko
cat /proc/devices

查看驱动号,为255
在这里插入图片描述
创建设备节点和设备挂钩

sudo mknod /dev/hello c 255 0

看到这个设备节点的详细信息

ls -l /dev/hello

在这里插入图片描述

5.编译$运行app

gcc app.c -o app
sudo ./app /dev/hello

输出为125,正确。
在这里插入图片描述

任务四 Linux中文件软连接和硬链接的验证实验

借鉴自:Linux系统硬链接和软链接具体实例讲解(超详细)

1.创建两个文件

echo “this is a test” >test.c
echo “this is a test2” >test2.c

2.创建一个软链接

软链接:ln -s 源文件 目标文件

ln -s   test.c  soft
ls -li           #查看目录下的信息

在这里插入图片描述

3.创建一个硬链接

硬链接:ln 源文件 目标文件

ln  test2.c  hard
ls -li

在这里插入图片描述
文件夹中文件
在这里插入图片描述

4.分析

在这里插入图片描述
在这里插入图片描述
通过上面两图:地址空间--------文件名

可以看出:

硬链接:和源文件同时是访问同一个地址空间,生成一个硬链接相当于copy一份该文件,如果删除源文件test.2.c,hard文件不会删除,文件的内容也是在的。

硬链接==复制

软链接相当于记录了源文件的地址,访问该软链接相当于直接访问该源文件如果删除源文件,该软链接也会相应丢失源文件内容,访问出错 。

软链接==快捷方式

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

华中科技大学操作系统实验课 实验四 的相关文章

  • grep 以特定字符串开头的行

    我想找到文件中以特定字符串开头的所有行 问题是 我事先不知道字符串里有什么 该值存储在变量中 天真的解决方案如下 grep my string file txt 因为如果 Bash 变量my string包含任何正则表达式特殊字符 grep
  • 如果等于特定值则替换列

    我希望替换 CSV 中的第四列 如果它等于 N A 我正在尝试将其更改为 1 我似乎无法让它发挥作用 awk F if 4 N A 4 1 test csv 您可以使用以下内容awk awk F 4 4 N A 1 4 1 OFS test
  • 如何将动态链接的应用程序转换为静态链接的应用程序?

    我有一个应用程序 例如 gedit 它是动态链接的 但我没有源代码 所以我不能按我喜欢的方式编译它 我想要做的是将其静态链接并将其移动到没有运行该应用程序所需的库的系统 那么是否可以做到以及如何做到呢 理论上是可能的 您基本上必须执行与动态
  • 当存储在变量中时,Git 提交消息变得混乱[重复]

    这个问题在这里已经有答案了 我有一个 Git 提交 其中有一个摘要 然后是一些描述 所以当我看到提交消息时git log format B n 1
  • posix 和 linux 特定函数的 C++ 包装器 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 您知道有什么好的库将 posix 和 linux 函数和结构 例如套接字或文件描述符 包装到 C 类中
  • 错误:‘:’标记之前需要初始化程序

    我正在尝试编译一些 C 代码 可以在 Windows 上使用 Visual Studio 2012 进行编译 g 4 4 我有这段代码 const std string cnw restoreSession const std vector
  • Bash 脚本在 for 循环中使用 sed 和变量?

    我正在尝试编写一个 bash 脚本 该脚本需要一些变量 然后使用 grep 对给定文件搜索进行查找 替换 以获取包含该字符串的文件列表 我认为我遇到的问题是在 sed 中看到变量我不确定它可能是什么 if searchFiles a old
  • $@ 中 args 的 bash 参数大小写

    我有一个带有一长串可选参数的脚本 有些具有相关的值 Such as script first 2012 12 25 last 2012 12 26 copy remove script first 2012 12 25 因此有以下案例陈述
  • 何时调用setsockopt?在bind()和connect()之前?

    我继承了一些 TCP 代码 调用 bind tcpSocket struct sockaddr server addr sizeof server addr 在致电之前 setsockopt tcpSocket SOL SOCKET SO
  • 很好的 C 库集合? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个很好的 ANSI C 库集合 用于处理向量 哈希映射 二进制树 字符串处理等 Try g
  • 将条目添加到 Linux 内核 .config 文件

    如何手动将 CONFIG XILINX FIXED DEVTREE ADDR y 行添加到 Linux 配置文件中 当我构建内核时它不断被覆盖 您可以通过以下方式构建make CONFIG XILINX FIXED DEVTREE ADDR
  • Cmake 错误未定义对“pthread_create”的引用

    我对 cmake FindThreads 进行了测试 这是我的源代码test cpp和CMakeLists txt include
  • C++向量数组运算符计算成本高?

    我一直都知道 C 的丰富抽象会带来一定的计算开销 但我的印象是 一旦应用了正确的编译器优化 这种开销几乎可以忽略不计 我很好奇这种开销到底有多大 所以我编写了一个简单的测试来确定这一点 该测试是一个模板化函数 它接受一个容器变量 为容器中的
  • Linux GCC 上 的 C++ 编译问题

    尝试过谷歌并在这里搜索 但没有运气 我正在尝试将一些使用 Windows 的代码移植到 Linux 上 然后我得到了大量的编译错误 我所做的只是 include
  • 使用 sysfs 的 Linux 用户空间 GPIO 中断

    我想使用 sysfs 在用户空间上使用 GPIO 中断 我使用这些命令 root at91 gpio109 gt echo 109 gt export root at91 gpio109 gt cd gpio109 root at91 gp
  • Motif 库的水平绘制的 RowColumn 类 (C)?

    我正在使用 Motif Library 来完成我的工作 如果有人不熟悉这个库 您可以在这里找到文件列表https packages ubuntu com xenial amd64 libmotif dev filelist https pa
  • ulimit -r 返回不同的值

    我将以下两行添加到系统范围的 etc security limits conf 中 soft rtprio 55 hard rtprio 55 系统重新启动后 根据我在计算机上访问用户帐户的方式 我会得到两个不同的结果 user clien
  • 共享库 RPATH 和二进制 RPATH 优先级

    如果共享库链接到二进制文件 并且共享库还依赖于其他库 则共享库的 RPATH 和二进制文件的 RPATH 的优先级 链接器搜索顺序 是什么 二进制文件的 RPATH 是否可以覆盖共享库中的 RPATH 我在共享库RPATH中设置的 ORIG
  • UNIX 域 STREAM 和 DATAGRAM 套接字之间的区别?

    这个问题是NOTSTREAM 类型和 DATAGRAM 类型 INTERNET 套接字之间的区别 我知道 STREAM 套接字使用 TCP 数据报套接字使用 UDP 以及所有 TCP UDP 内容 按顺序到达的数据包 ACK NACK 等
  • 使用sed插入文件内容

    我试图在给定模式之前插入文件内容 这是我的代码 sed i pattern i r scriptPath adapters default permissions xml manifestFile 它添加路径而不是文件的内容 有任何想法吗

随机推荐

  • ElementUI浅尝辄止23:Loading 加载

    Loading加载组件 加载数据时显示动效 常见于加载数据量大的业务操作 附带动态效果 1 如何使用 区域加载 在表格等容器中加载数据时显示 Element 提供了两种调用 Loading 的方法 指令和服务 对于自定义指令v loadin
  • linux重置root用户密码

    重置root密码 法一 rd break 第 1 步 重启系统编辑内核参数 第 2 步 找到 linux 这行 在此行末尾空格后输入rd break End键也可直接进入行尾 成功后显示页面为 第 3 步 查看 可选 该步骤可省略 命令为
  • 把一个数组的第三到第六位之间的元素删除 形成一个新的数组

    思路一 找到第三和第六之间的4和5位 也就是下标位3和4的元素 删除之后再前移 思路二 找到第三和第六之间的4和5位 也就是下标位3和4的元素 运用if中continue关键字跳过这两个位置 思路一和思路二的区别是思路一元素前移最后两位是0
  • fio测试磁盘性能

    rwmixwrite是fio命令中一个用于指定读写比例的参数 它的含义是在随机读写的情况下 写操作的百分比 例如 rwmixwrite 30表示30 的操作是写操作 70 的操作是读操作 以下是一个示例命令 fio name mytest
  • 帝国cms发送ajax请求,[分享]美化ajax弹出的提示信息

    前台页面只需要在内容模板里面加上这两个文件 然后再修改一下 e data js ajax js var http request false function makeRequest url functionName httpType
  • 收藏学习!15个使用率超高的Python库

    今天给大家分享最近一年内PyPI上下载量最高的Python包 现在我们来看看这些包的作用 他们之间的关系 以及为什么如此流行 1 Urllib3 8 93亿次下载 Urllib3 是 Python 的 HTTP 客户端 它提供了许多 Pyt
  • Keil 5出现Error: L6218E: Undefined symbol解决方法

    目录 1 找到相关未定义函数 选中然后右击 GO TO Reference To ADC Cmd 2 发现该函数在stm32f10x adc h中 3 可以看到右边fwlib里没有相应 c文件 我们添加上 4 右击 选择manage pro
  • HTML怎么插入一段代码

    之前学习了点HTML的基础知识 在工作中给别人发邮件的时候 使用HTML插入超链接 这回需要插入一段代码块 语法 pre pre 将需要传入的代码放在 pre 和 pre 之间就可以了 浏览器自动识别 示例 p 这是一段代码块 p pre
  • linux查看内存占用情况(top、free、ps)

    top命令 top命令是Linux下常用的性能分析工具 能够实时显示系统中各个进程的资源占用状况 类似于Windows的任务管理器 运行 top 命令后 CPU 使用状态会以全屏的方式显示 并且会处在对话的模式 用基于 top 的命令 可以
  • Embedded Linux Conference Europe schedule posted

    From http linuxgizmos com embedded linux conference europe schedule posted The Linux Foundation posted a schedule for Li
  • 2023 年程序员的最佳工作角色

    当今价值数十亿美元的计算机编程市场正受到下一代应用程序和产品的日益普及的推动 例如自动编码 统计计算 数据分析 ML 机器学习 和 AI 人工智能 根据MarketsandMarkets的一项研究 到11年 全球CAC 计算机辅助编码 行业
  • Redis三种集群架构

    一 主从架构 搭建主从结构 从节点配置步骤 1 复制一份redis conf文件 2 将相关配置修改为如下值 port 6380 pidfile var run redis 6380 pid 把pid进程号写入pidfile配置的文件 lo
  • 统计学第九周:参数估计python实现

    统计学第九周 参数估计复习 参数估计 根据从总体中随机取样获得样本 根据取样样本来估计总体分布中参数的过程 方法 估计形式上分 点估计与区间估计 估计的方法有矩法估计 最小二乘法估计 似然估计 贝叶斯估计等等 问题一般有 未知参数的估计量
  • 期货方法(期货方法很简单 只用MACD)

    期货法 在期货市场上 95 的人都是赔钱的 对于期货市场的新手来说 一定要有一个清晰的认识 95 的数字告诉我们什么 它只是告诉我们 在获得稳定的利润之前 我们不应该投入太多的钱 对于初学者来说 投入的钱越多 损失的钱就越多 所以一定要控制
  • 渗透之Aircrack—wifi破解

    环境 kali 工具使用 无线网卡 型号雷凌RT3070L 注意型号选择的使用 不同型号可能导致kali无法识别 步骤总结 1 kali连接外接无线网卡 2 ifconfig查看网卡信息 新出现的wlan0网卡 3 开启网卡监听模式 air
  • 实践积累:用Vue3简单写一个单行横向滚动组件

    目录 效果图 需求分析 实现分析 样式展示分析 变量分析 方法分析 实现步骤 1 实现模板 2 实现css 3 首先获取list 4 页面挂载后监听groupBoxRef的scroll事件并获取当前的滚动位置 5 计算展示的宽度显隐箭头 当
  • 讲透JVM类加载机制,向高手进阶!

    目录 前言 JVM在什么情况下会加载一个类 从实用角度出发 来看看验证 准备和初始化的过程 核心阶段 初始化 类加载器和双亲委派机制 1 前言 先来看一下JVM整体的一个运行原理 我们首先从 java 代码文件 编译成 class 字节码文
  • 运放的虚短和虚断以及分类

    放大器定义 能实现信号 功率放大的器件 称为放大器 英文为Amplifier 以放大器为核心 能实现放大功能的电路组合 称为放大电路 放大器的种类 全部放大器被分为三种 晶体管放大器 运算放大器和功能放大器 晶体管及其放大电路的复杂 从静态
  • 哈希表(散列表)原理详解

    什么是哈希表 哈希表 Hash table 也叫散列表 是根据关键码值 Key value 而直接进行访问的数据结构 也就是说 它通过把关键码值映射到表中一个位置来访问记录 以加快查找的速度 这个映射函数叫做散列函数 存放记录的数组叫做散列
  • 华中科技大学操作系统实验课 实验四

    一 实验目的 1 理解设备是文件的概念 2 掌握Linux模块 驱动的概念和编程流程 3 Windows Linux下掌握文件读写基本操作 二 实验内容 1 编写一个Linux内核模块 并完成模块的安装 卸载等操作 2 编写Linux驱动程