当前位置: 首页 > news >正文

Doing It in User Space

Doing It in User Space

A Unix programmer who's addressing kernel issues for the first time might be nervous about writing a module. Writing a user program that reads and writes directly to the device ports may be easier. 第一次解决内核问题的 Unix 程序员可能对编写模块感到紧张。 编写直接读取和写入设备端口的用户程序可能更容易。

Indeed, there are some arguments in favor of user-space programming, and sometimes writing a so-called user-space device driver is a wise alternative to kernel hacking. In this section, we discuss some of the reasons why you might write a driver in user space. This book is about kernel-space drivers, however, so we do not go beyond this introductory discussion. 确实,有一些支持用户空间编程的论据,有时编写所谓的用户空间设备驱动程序是内核黑客的明智选择。 在本节中,我们将讨论您可能在用户空间中编写驱动程序的一些原因。 然而,这本书是关于内核空间驱动程序的,所以我们不会超出这个介绍性讨论。

The advantages of user-space drivers are: 用户空间驱动程序的优点是

The full C library can be linked in. The driver can perform many exotic tasks without resorting to external programs (the utility programs implementing usage policies that are usually distributed along with the driver itself). 可以链接完整的 C 库。驱动程序可以执行许多奇异的任务,而无需借助外部程序(实现使用策略的实用程序通常与驱动程序本身一起分发)。

The programmer can run a conventional debugger on the driver code without having to go through contortions to debug a running kernel. 程序员可以在驱动程序代码上运行传统的调试器,而无需通过扭曲来调试正在运行的内核。

If a user-space driver hangs, you can simply kill it. Problems with the driver are unlikely to hang the entire system, unless the hardware being controlled is really misbehaving. 如果用户空间驱动程序挂起,您可以简单地杀死它。 驱动程序的问题不太可能导致整个系统挂起,除非被控制的硬件确实行为不端。

User memory is swappable, unlike kernel memory. An infrequently used device with a huge driver won't occupy RAM that other programs could be using, except when it is actually in use. 与内核内存不同,用户内存是可交换的。 一个不经常使用的具有巨大驱动程序的设备不会占用其他程序可能正在使用的 RAM,除非它实际在使用中。

A well-designed driver program can still, like kernel-space drivers, allow concurrent access to a device. 一个设计良好的驱动程序仍然可以像内核空间驱动程序一样允许对设备进行并发访问。

If you must write a closed-source driver, the user-space option makes it easier for you to avoid ambiguous licensing situations and problems with changing kernel interfaces. 如果您必须编写闭源驱动程序,则用户空间选项可以让您更轻松地避免不明确的许可情况和时常变化的内核接口的问题。

For example, USB drivers can be written for user space; see the (still young) libusb project at libusb.sourceforge.net and "gadgetfs" in the kernel source. Another example is the X server: it knows exactly what the hardware can do and what it can't, and it offers the graphic resources to all X clients. Note, however, that there is a slow but steady drift toward frame-buffer-based graphics environments, where the X server acts only as a server based on a real kernel-space device driver for actual graphic manipulation. 例如,可以为用户空间编写 USB 驱动程序; 请参阅 libusb.sourceforge.net 上的(仍然年轻的)libusb 项目和内核源代码中的“gadgetfs”。 另一个例子是 X 服务器:它确切地知道硬件能做什么和不能做什么,它为所有 X 客户端提供图形资源。 但是请注意,向基于帧缓冲区的图形环境发展缓慢而稳定,在这种环境中,X 服务器仅充当基于真正内核空间设备驱动程序的服务器,用于实际的图形操作。

Usually, the writer of a user-space driver implements a server process, taking over from the kernel the task of being the single agent in charge of hardware control. Client applications can then connect to the server to perform actual communication with the device; therefore, a smart driver process can allow concurrent access to the device. This is exactly how the X server works. 通常,用户空间驱动程序的编写者实现了一个服务器进程,从内核中接管了作为负责硬件控制的单一代理的任务。 然后客户端应用程序可以连接到服务器以执行与设备的实际通信; 因此,智能驱动程序进程可以允许对设备的并发访问。 这正是 X 服务器的工作方式。

But the user-space approach to device driving has a number of drawbacks. The most important are: 但是设备驱动的用户空间方法有许多缺点。 最重要的是:

Interrupts are not available in user space. There are workarounds for this limitation on some platforms, such as the vm86 system call on the IA32 architecture. 中断在用户空间中不可用。 在某些平台上存在此限制的解决方法,例如 IA32 架构上的 vm86 系统调用。

Direct access to memory is possible only by mmapping /dev/mem, and only a privileged user can do that. 只有通过 mmaping /dev/mem 才能直接访问内存,并且只有特权用户可以这样做。

Access to I/O ports is available only after calling ioperm or iopl. Moreover, not all platforms support these system calls, and access to /dev/port can be too slow to be effective. Both the system calls and the device file are reserved to a privileged user. 只有在调用 ioperm 或 iopl 后才能访问 I/O 端口。 此外,并非所有平台都支持这些系统调用,并且访问 /dev/port 可能太慢而无法生效。 系统调用和设备文件都保留给特权用户。

Response time is slower, because a context switch is required to transfer information or actions between the client and the hardware. 响应时间较慢,因为需要上下文切换来在客户端和硬件之间传输信息或操作。

Worse yet, if the driver has been swapped to disk, response time is unacceptably long. Using the mlock system call might help, but usually you'll need to lock many memory pages, because a user-space program depends on a lot of library code. mlock, too, is limited to privileged users. 更糟糕的是,如果驱动程序已被交换到磁盘,响应时间长得令人无法接受。 使用 mlock 系统调用可能会有所帮助,但通常您需要锁定许多内存页面,因为用户空间程序依赖于大量库代码。 mlock 也仅限于特权用户。

The most important devices can't be handled in user space, including, but not limited to, network interfaces and block devices. 最重要的设备无法在用户空间中处理,包括但不限于网络接口和块设备。

As you see, user-space drivers can't do that much after all. Interesting applications nonetheless exist: for example, support for SCSI scanner devices (implemented by the SANE package) and CD writers (implemented by cdrecord and other tools). In both cases, user-level device drivers rely on the "SCSI generic" kernel driver, which exports low-level SCSI functionality to user-space programs so they can drive their own hardware. 如您所见,用户空间驱动程序毕竟不能做那么多。 尽管如此,仍然存在有趣的应用程序:例如,支持 SCSI 扫描仪设备(由 SANE 包实现)和 CD 刻录机(由 cdrecord 和其他工具实现)。 在这两种情况下,用户级设备驱动程序都依赖于“SCSI 通用”内核驱动程序,它将低级 SCSI 功能导出到用户空间程序,以便它们可以驱动自己的硬件。

One case in which working in user space might make sense is when you are beginning to deal with new and unusual hardware. This way you can learn to manage your hardware without the risk of hanging the whole system. Once you've done that, encapsulating the software in a kernel module should be a painless operation. 在用户空间工作可能有意义的一种情况是当您开始处理新的和不寻常的硬件时。 通过这种方式,您可以学习管理您的硬件,而不会有挂起整个系统的风险。 完成此操作后,将软件封装在内核模块中应该是一项轻松的操作。

Quick Reference

This section summarizes the kernel functions, variables, macros, and /proc files that we've touched on in this chapter. It is meant to act as a reference. Each item is listed after the relevant header file, if any. A similar section appears at the end of almost every chapter from here on, summarizing the new symbols introduced in the chapter. Entries in this section generally appear in the same order in which they were introduced in the chapter: 本节总结了我们在本章中涉及的内核函数、变量、宏和 /proc 文件。 它旨在作为参考。 每个项目都列在相关头文件之后(如果有)。 从这里开始,几乎每一章的末尾都会出现一个类似的部分,总结本章中引入的新符号。 本节中的条目通常按照它们在本章中介绍的顺序出现:

insmod
modprobe
rmmod

User-space utilities that load modules into the running kernels and remove them. 将模块加载到正在运行的内核中并删除它们的用户空间实用程序。

#include <linux/init.h>
module_init(init_function);
module_exit(cleanup_function);

Macros that designate a module's initialization and cleanup functions. 指定模块的初始化和清理功能的宏。

_ _init
_ _initdata
_ _exit
_ _exitdata

Markers for functions (_ _init and _ _exit) and data (_ _initdata and _ _exitdata) that are only used at module initialization or cleanup time. Items marked for initialization may be discarded once initialization completes; the exit items may be discarded if module unloading has not been configured into the kernel. These markers work by causing the relevant objects to be placed in a special ELF section in the executable file. 仅在模块初始化或清理时使用的函数(_ _init 和 _ _exit)和数据(_ _initdata 和 _ _exitdata)的标记。 一旦初始化完成,标记为初始化的项目可能会被丢弃; 如果模块卸载尚未配置到内核中,则退出项可能会被丢弃。 这些标记通过将相关对象放置在可执行文件的特殊 ELF 部分中来工作。

#include <linux/sched.h>

One of the most important header files. This file contains definitions of much of the kernel API used by the driver, including functions for sleeping and numerous variable declarations. 最重要的头文件之一。 该文件包含驱动程序使用的大部分内核 API 的定义,包括休眠函数和大量变量声明。

struct task_struct *current;

The current process. 当前进程。

current->pid
current->comm

The process ID and command name for the current process. 当前进程的进程 ID 和命令名称。

obj-m

A makefile symbol used by the kernel build system to determine which modules should be built in the current directory. 内核构建系统使用的 makefile 符号,用于确定应在当前目录中构建哪些模块。

/sys/module
/proc/modules

/sys/module is a sysfs directory hierarchy containing information on currently-loaded modules. /proc/modules is the older, single-file version of that information. Entries contain the module name, the amount of memory each module occupies, and the usage count. Extra strings are appended to each line to specify flags that are currently active for the module. /sys/module 是一个 sysfs 目录层次结构,其中包含有关当前加载的模块的信息。 /proc/modules 是该信息的较旧的单文件版本。 条目包含模块名称、每个模块占用的内存量以及使用次数。 额外的字符串附加到每一行以指定模块当前处于活动状态的标志。

vermagic.o

An object file from the kernel source directory that describes the environment a module was built for. 内核源目录中的目标文件,描述了构建模块的环境。

#include <linux/module.h>

Required header. It must be included by a module source. 必需的标头。 它必须包含在模块源代码中。

#include <linux/version.h>

A header file containing information on the version of the kernel being built. 包含有关正在构建的内核版本信息的头文件。

LINUX_VERSION_CODE

Integer macro, useful to #ifdef version dependencies. 整数宏,对#ifdef 版本依赖很有用。

EXPORT_SYMBOL (symbol);
EXPORT_SYMBOL_GPL (symbol);

Macro used to export a symbol to the kernel. The second form limits use of the exported symbol to GPL-licensed modules. 用于将符号导出到内核的宏。 第二种形式将导出符号的使用限制为 GPL 许可的模块。

MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);

Place documentation on the module in the object file. 将有关模块的文档放在目标文件中。

MODULE_LICENSE(license);

Declare the license governing this module. 声明管理此模块的许可证。

#include <linux/moduleparam.h>
module_param(variable, type, perm);

Macro that creates a module parameter that can be adjusted by the user when the module is loaded (or at boot time for built-in code). The type can be one of bool, charp, int, invbool, long, short, ushort, uint, ulong, or intarray. 创建模块参数的宏,用户可以在加载模块时(或在启动时为内置代码)调整该参数。 类型可以是 bool、charp、int、invbool、long、short、ushort、uint、ulong 或 intarray 之一。

#include <linux/kernel.h>
int printk(const char * fmt, ...);

The analogue of printf for kernel code. 内核代码的 printf 类似物。


[1] The priority is just a string, such as <1>, which is prepended to the printk format string. Note the lack of a comma after KERN_ALERT; adding a comma there is a common and annoying typo (which, fortunately, is caught by the compiler). 优先级只是一个字符串,例如 <1>,它被添加到 printk 格式字符串的前面。 注意 KERN_ALERT 后面没有逗号; 添加逗号有一个常见且烦人的错字(幸运的是,编译器已捕获)。

[2] This allows up to 256 development versions between stable versions. 这允许在稳定版本之间最多有 256 个开发版本。

[3] As of this writing, there is talk of moving parameters elsewhere within sysfs, however. 然而,在撰写本文时,有人谈到在 sysfs 中的其他地方移动参数。

相关文章:

  • Vue2:网易云播放音乐并实现同步一次显示一行歌词
  • 这四个问题处理好,无人机集群编队研究会有新突破
  • 【JavaSE】之JVM入门(上)
  • 《计算机视觉基础知识蓝皮书》第7篇 模型优化方法及思路
  • java毕业设计牙科诊所管理系统Mybatis+系统+数据库+调试部署
  • 蓝桥杯2022年(本科c++b组)
  • pytorch :OSError: [WinError 1455] 页面文件太小,无法完成操作。 Error loading 【已解决】
  • 【BData12】Hadoop HDFSMapReduse
  • 阿里MySQL应用实战与性能调优手册惨遭泄漏,GitHub下载量超23K+
  • 软件测试简历包装我们会了,但测试人的自我“包装”呢?HR自我介绍包装小技巧【建议收藏】
  • Spring 注解开发下的依赖注入(自动装配)(引用类型)(普通类型)(加载properties文件)
  • 机器学习之决策树
  • 单链表、顺序表实操小项目---通讯录
  • 【C语言进阶】简易通讯录的实现
  • springboot+springcloudgateway+nacos+sleuth+zipkin+mysql
  • JS 中的深拷贝与浅拷贝
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • Angular4 模板式表单用法以及验证
  • nodejs调试方法
  • PermissionScope Swift4 兼容问题
  • quasar-framework cnodejs社区
  • React组件设计模式(一)
  • spring boot 整合mybatis 无法输出sql的问题
  • SpringBoot 实战 (三) | 配置文件详解
  • 爱情 北京女病人
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 开源地图数据可视化库——mapnik
  • 前端存储 - localStorage
  • 微服务框架lagom
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • 详解NodeJs流之一
  • 【云吞铺子】性能抖动剖析(二)
  • ​linux启动进程的方式
  • #pragma pack(1)
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (一) storm的集群安装与配置
  • (转)ObjectiveC 深浅拷贝学习
  • (转)详解PHP处理密码的几种方式
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET导入Excel数据
  • .NET分布式缓存Memcached从入门到实战
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • [20160902]rm -rf的惨案.txt
  • [20171102]视图v$session中process字段含义