如何为内核 5.10.x 模块驱动程序版本替换 set_fs(KERNEL_DS)

如何解决如何为内核 5.10.x 模块驱动程序版本替换 set_fs(KERNEL_DS)

我一直在将自定义模块驱动程序更新为 5.10.x linux 内核版本。我的驱动程序在 cdc-acm 设备上添加了一层。为了复制行为,使用了下一个小驱动程序。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/tty.h>
#include <linux/version.h>
#include <linux/uaccess.h>



/* Device major umber */
static int major;

/* ttyACM file descriptor */
static struct file *fd;


/* Private functions ---------------------------------------------------------*/
static int usbox_serial_baudrate_set(struct file *fd)
{
    int ret;
    mm_segment_t old_fs;
    struct termios newtio;
    //struct termios __user newtio;
    //void __user *unewtio = (void __user *) &newtio;

    memset(&newtio,sizeof(newtio));
    newtio.c_cflag = (B115200 | CS8 | CLOCAL | CREAD);

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0)
    old_fs = get_fs();
    set_fs( get_ds() );
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0)
    old_fs = get_fs();
    set_fs( KERNEL_DS );
#else
    old_fs = force_uaccess_begin();
#endif

    if (fd->f_op->unlocked_ioctl) {
        ret = fd->f_op->unlocked_ioctl(fd,TCSETS,(unsigned long int) &newtio);
        pr_info("_unlocked_ioctl: %d\n",ret);
    } else {
        ret = -ENOTTY;
    }

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0)
    set_fs(old_fs);
#else
    force_uaccess_end(old_fs);
#endif

    pr_info("ret: %d\n",ret );
    return ret;
}


/* Driver Methods ------------------------------------------------------------*/
static ssize_t testdrv_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
    return 0;
}

static ssize_t testdrv_write(struct file *filp,const char __user *buf,loff_t *ppos)
{
    return 0;
}

static int testdrv_open(struct inode *inode,struct file *filp)
{
    pr_info("testdrv_open\n");

    fd = filp_open( "/dev/ttyACM0",O_RDWR|O_NOCTTY,0);
    if (IS_ERR(fd)) {
        pr_info("error from filp_open()\n");
        return -ENODEV;
    }

    pr_info ("fd      : %p\n",fd);
    pr_info ("fd->f_op: %p\n",fd->f_op);
    pr_info ("ioctl   : %p\n",fd->f_op->unlocked_ioctl);

    if ((fd->f_op == NULL) || (fd->f_op->unlocked_ioctl == NULL)) {
        pr_info("errno: ENODEV\n");
        return -ENODEV;
    }

    // Set baudrate.
    if (usbox_serial_baudrate_set(fd) != 0 ) {
        filp_close(fd,NULL);
        pr_info("errno: EINVAL\n");
        return -EINVAL;
    }

    return 0;
}

static int testdrv_release(struct inode *inode,struct file *filp)
{
    pr_info("testdrv_release\n");

    if (fd != NULL) {
        filp_close(fd,NULL);
        fd = NULL;
    }

    return 0;
}

static struct file_operations testdrv_fops = {
    .owner      = THIS_MODULE,.read       = testdrv_read,.write      = testdrv_write,.open       = testdrv_open,.release    = testdrv_release
};


/* Module stuff --------------------------------------------------------------*/

static int __init testdrv_init(void)
{
    int ret;

    ret = register_chrdev(0,"testdrv",&testdrv_fops);
    if (ret < 0) {
        pr_err("Error %d\n",ret);
        return ret;
    }
    major = ret;
    fd = NULL;
    pr_info("Major %d\n",major);

    return 0;
}

static void __exit testdrv_exit(void)
{
    unregister_chrdev(major,"testdrv");
}

module_init(testdrv_init);
module_exit(testdrv_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Unknonw");
MODULE_DESCRIPTION("testdrv");

这里,当testdrv打开时,驱动打开ttyACM相关。然后它调用“usbox_serial_baudrate_set”来设置波特率。此函数从填充描述符调用“unlocked_ioctl”。为了能够使用这个调用,我必须使用

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0)
    old_fs = get_fs();
    set_fs( KERNEL_DS );
#else
    old_fs = force_uaccess_begin();
#endif
...
        ret = fd->f_op->unlocked_ioctl(fd,(unsigned long int) &newtio);
...
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0)
    set_fs(old_fs);
#else
    force_uaccess_end(old_fs);
#endif

在 5.10.x 之前,此代码运行正常。我不得不使用 KERNEL_DS 对 5.4.x 做一些小改动,但现在我总是从“unlocked_ioctl”得到一个 EFAULT。我试过删除“force_uaccess_begin / force_uaccess_end”,但没有成功。 'unlocked_ioctl' 最终调用 /drivers/tty/tty_ioctl.c 'set_termios' 函数并失败:

#ifdef TCGETS2
    } else if (opt & TERMIOS_OLD) {
        if (user_termios_to_kernel_termios_1(&tmp_termios,(struct termios __user *)arg))
            return -EFAULT;
    } else {

函数'user_termios_to_kernel_termios_1'是一个宏

#define user_termios_to_kernel_termios_1(k,u) copy_from_user(k,u,sizeof(struct termios))

使用 4.15.0 内核,一旦插入模块,我就会在 dmesg 中收到下一条消息,并与设备相关:

[370099.242677] testdrv:testdrv_init: Major 237
[370103.032357] testdrv:testdrv_open: testdrv_open
[370103.032635] testdrv:testdrv_open: fd      : 0000000034db75d4
[370103.032637] testdrv:testdrv_open: fd->f_op: 00000000c761e065
[370103.032638] testdrv:testdrv_open: ioctl   : 00000000608ed60c
[370103.032643] testdrv:usbox_serial_baudrate_set: _unlocked_ioctl: 0
[370103.032645] testdrv:usbox_serial_baudrate_set: ret: 0
[370103.032685] testdrv:testdrv_release: testdrv_release

并带有 5.10.1

[  294.418308] testdrv:testdrv_init: got major 244
[  296.574583] testdrv:testdrv_open: testdrv_open
[  296.575949] testdrv:testdrv_open: fd      : 00000000c35e59c0
[  296.575955] testdrv:testdrv_open: fd->f_op: 0000000041840a0e
[  296.575957] testdrv:testdrv_open: ioctl   : 000000005e21689c
[  296.575965] testdrv:usbox_serial_baudrate_set: _unlocked_ioctl: -14
[  296.575967] testdrv:usbox_serial_baudrate_set: ret: -14
[  296.575970] testdrv:testdrv_open: errno: EINVAL

任何人都可以帮助我了解发生了什么?混合用户空间/内核空间数据有问题吗?我该如何解决?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-