编写适用于 Oracle® Solaris 11.2 的设备驱动程序

退出打印视图

更新时间: 2014 年 9 月
 
 

设置测试模块

使用 /etc 目录中的 system(4) 文件可在引导时设置内核变量的值。使用内核变量,可在驱动程序中切换不同的行为,并利用内核提供的调试功能。内核变量 moddebug 和 kmem_flags 在调试中非常有用,本节稍后将对其进行讨论。另请参见Using the Deadman Feature

由于仅在内核引导时读取一次 /etc/system,因此引导后对内核变量所做的更改不可靠。修改此文件后,必须重新引导系统,更改才能生效。如果文件中的更改导致系统无法工作,请使用询问功能 (-a) 选项进行引导。然后,将 /dev/null 指定为系统文件。


注 - 后续发行版中不一定存在内核变量。

设置内核变量

set 命令可以更改模块变量或内核变量的值。要设置模块变量,请指定模块名称和变量:

set module_name:variable=value

例如,要在名为 myTest 的驱动程序中设置变量 test_debug,请按如下方式使用 set

% set myTest:test_debug=1

要设置由内核自身导出的变量,可忽略模块名称。

还可以使用按位 OR 运算设置值,例如:

% set moddebug | 0x80000000

装入和卸载测试模块

使用命令 modload(1M)modunload(1M)modinfo(1M) 可以添加测试模块,在对驱动程序进行调试和压力测试时,这是一种非常有用的方法。正常操作中通常不需要这些命令,因为内核会自动装入需要的模块并卸载未使用的模块。moddebug 内核变量可与这些命令一起使用,以提供信息并设置控制。

使用 modload() 函数

使用 modload(1M) 可将模块强制装入内存。modload 命令可验证装入驱动程序时该驱动程序是否具有未解析的引用。装入驱动程序并表明该驱动程序一定可以连接。驱动程序成功装入时,将调用该驱动程序的 _info(9E) 入口点,但不一定调用 attach() 入口点。

使用 modinfo() 函数

使用 modinfo(1M) 可以确认驱动程序已装入。

示例 23-3  使用 modinfo 确认已装入的驱动程序
$ modinfo
 Id Loadaddr   Size Info Rev Module Name
  6 101b6000    732   -   1  obpsym (OBP symbol callbacks)
  7 101b65bd  1acd0 226   1  rpcmod (RPC syscall)
  7 101b65bd  1acd0 226   1  rpcmod (32-bit RPC syscall)
  7 101b65bd  1acd0   1   1  rpcmod (rpc interface str mod)
  8 101ce8dd  74600   0   1  ip (IP STREAMS module)
  8 101ce8dd  74600   3   1  ip (IP STREAMS device)
...
$ modinfo | grep mydriver
169 781a8d78   13fb   0   1  mydriver (Test Driver 1.5)

info 字段中的数字是为驱动程序选择的主设备号。如果提供了模块 ID,则可使用 modunload(1M) 命令来卸载模块。模块 ID 位于 modinfo 输出的左列中。

有时,发出 modunload 后驱动程序不会按预期卸载,因为该驱动程序被确定处于忙状态。由于驱动程序确实繁忙或 detach 入口点未正确实现而导致驱动程序无法执行 detach(9E) 时,会出现上述情况。

使用 modunload()

要从内存中删除所有当前未使用的模块,请使用模块 ID 0 运行 modunload(1M):

# modunload -i 0
设置 moddebug 内核变量

moddebug 内核变量可控制模块装入过程。moddebug 的可能值包括:

0x80000000

装入或卸载模块时向控制台列显消息。

0x40000000

提供更详细的错误消息。

0x20000000

装入或卸载时列显更多详细信息,如包含地址和大小。

0x00001000

不自动卸载驱动程序。系统资源变少时,系统不尝试卸载设备驱动程序。

0x00000080

不自动卸载流。系统资源变少时,系统不尝试卸载 STREAMS 模块。

0x00000010

不自动卸载任何类型的内核模块。

0x00000001

如果与 kmdb 一起运行,moddebug 会导致执行断点,并在调用每个模块的 _init() 例程之前立即返回到 kmdb。此设置还会在执行模块的 _info()_fini() 例程时生成其他调试消息。

设置 kmem_flags 调试标志

kmem_flags 内核变量用于启用内核的内存分配器中的调试功能。将 kmem_flags 设置为 0xf 即启用分配器的调试功能。这些功能包括运行时检查,以找出以下代码条件:

  • 释放缓冲区后向缓冲区写入

  • 初始化内存之前使用内存

  • 写入时已过缓冲区结尾

Oracle Solaris Modular Debugger Guide介绍了如何使用内核内存分配器来分析此类问题。


注 - 在将 kmem_flags 设置为 0xf 的情况下进行测试和开发有助于检测潜在的内存损坏错误。由于将 kmem_flags 设置为 0xf 会更改内核内存分配器的内部行为,因此最好应不使用 kmem_flags 而执行全面测试。