Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1283942
  • 博文数量: 554
  • 博客积分: 10425
  • 博客等级: 上将
  • 技术积分: 7555
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-09 09:49
文章分类

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-08 16:50:56


上一页:Solaris 操作系统的定义


内核概述
内核管理系统资源,包括文件系统、进程和物理设备。内核为应用程序提供了系统服务,例如 I/O 管理、虚拟内存和调度。内核协调所有用户进程和系统资源的交互。内核分配优先级、服务资源请求和服务硬件中断与异常。内核调度和切换线程,将内存分页和交换进程。

内核模块与用户程序之间的差异
本节讨论内核模块与用户程序之间的一些重要差异。

内核模块与用户程序之间的执行差异
内核模块的以下特性突出说明了内核模块与用户程序在执行上的重要差异:

内核模块具有独立的地址空间。模块运行在内核空间中。应用程序运行在用户空间中。系统软件受到保护,不允许用户程序访问。内核空间和用户空间有各自独立的内存地址空间。请参阅 User and Kernel Address Spaces on x86 and SPARC Machines 了解更多关于地址空间的重要信息。

内核模块具有更高的执行特权。运行在内核空间中的代码要比运行在用户空间中的代码具有更大的特权。由于驱动程序模块对系统的影响要远远大于对用户程序的影响,所以请认真、全面地测试驱动程序模块,以避免为系统带来负面的影响。请参阅 设备驱动程序测试技巧。

内核模块不按顺序执行。用户程序通常按顺序执行并且从头到尾地执行单独的任务。内核模块并不按顺序执行,它注册自己是为了服务将来的请求。

内核模块可以被中断。在同一时刻,可能有许多进程同时向驱动程序发出请求。中断程序可以在驱动程序正在响应系统调用时,向驱动程序发出请求。在对称多处理器(SMP)系统中,驱动程序可能在多个 CPU 上并发地执行。

内核模块必须是可抢占的。您不能仅仅因为驱动程序代码不会造成阻塞,就认为驱动程序代码是安全的。应该在假设驱动程序可能会被抢占的情况下设计驱动程序。

内核模块能够共享数据。一个应用程序的不同线程常常不会共享数据。与之相对应的是,组成驱动程序的数据结构和例程被所有使用驱动程序的线程所共享。驱动程序必须能够处理由多个请求导致的竞争问题。请仔细设计驱动程序数据结构以保持多个线程的独立执行。驱动程序必须在不破坏共享数据的条件下访问共享数据。请参阅 Writing Device Drivers 一书中的第 3 章,Multithreading 和 Multithreaded Programming Guide 一书。

内核模块与用户模块之间的结构差异
内核模块的以下特性突出说明了内核模块与用户程序在结构上的重要差异:

内核模块不定义主程序。内核模块,包括设备驱动程序在内,没有 main() 例程。取而代之的是,内核模块含有许多子例程和数据。设备驱动程序是构成指向输入/输出(I/O)设备软件接口的内核模块。设备驱动程序中的子例程提供了通向设备的入口点。内核使用设备编号属性来定位 open() 例程和其他正确的设备驱动程序例程。请参阅设备驱动程序了解关于入口点的更多信息。请参阅设备编号了解关于设备编号的更多信息。

内核模块只连接到内核。内核模块不在用户程序连接的同一个库中进行连接。内核模块唯一可以调用的函数只是那些内核提供给外部的函数。如果驱动程序引用了未在内核中定义的符号,虽然驱动程序可以编译但是无法加载。Solaris OS 驱动程序模块应该使用规定的 DDI/DKI (设备驱动程序接口/驱动程序内核接口)接口。 当您使用了这些标准的接口,您无需重新编译驱动程序就可以升级到新的 Solaris 版本或者迁移到一个新的平台。了解更多关于 DDI 的信息,请参阅 Writing Device Drivers 一书中的 DDI/DKI Interfaces。在连接编辑期间,通过使用 -N 选项,内核模块可以依赖其他内核模块。请参阅 ld(1) 手册页了解更多相关信息。

内核模块使用不同的头文件。与用户程序相比,内核模块需要不同的头文件集合。手册页为每一个函数列出了所需的头文件。请参阅 man pages section 9: DDI and DKI Kernel Functions 获取 DDI/DKI 函数的更多信息,参阅 man pages section 9: DDI and DKI Driver Entry Points 获取入口点的更多信息,参阅 man pages section 9: DDI and DKI Properties and Data Structures 获取结构的更多信息。内核模块可以包含用户程序所共享的头文件,如果用户和内核接口在这种共享头文件中,则需要使用 _KERNEL 宏有条件地进行定义。

内核模块应该避免使用全局变量。在内核模块中避免使用全局变量要比在用户程序中避免使用全局变量更加重要。请尽可能地将符号声明为 static。如果必须使用全局符号,请为它们增加一个内核中独一无二的前缀。为模块中的私有符号使用前缀也是一个好的实践。

内核模块可以针对硬件进行定制。内核模块可以将进程注册表用于特定角色。内核代码可以针对特定处理器进行优化。

内核模块可以动态加载。组成设备驱动程序的子例程和数据的集合可以编译成单独的可加载目标代码模块。然后这个可加载模块可以静态或动态地与内核连接或脱离。当系统运行时,您可以直接向内核添加功能。无需重新引导系统,您就可以测试新版本的驱动程序。

内核模块与用户程序之间的数据传输差异
设备与系统间的传输速度通常低于 CPU 内部的数据传输速度。因此,驱动程序通常将正在调用的线程挂起,直到数据传输完毕。当调用驱动程序的线程挂起时,CPU 可以有时间执行其他线程。数据传输完毕时,设备会发送一个中断。驱动程序处理从该设备接收的中断。驱动程序随后通知 CPU 恢复执行刚才正在调用的线程。请参阅 Writing Device Drivers 一书的第 8 章 Interrupt Handlers。

驱动程序必须与用户进程(虚拟的)地址、系统(内核)地址和 I/O 总线地址协同工作。驱动程序有时将数据从一个地址空间拷贝到另一个地址空间,有时仅操纵地址映射表。请参阅 Writing Device Drivers 一书中的 Bus Architectures 。

x86 和 SPARC 机器的用户和内核地址空间
在x86 机器上的 Solaris 系统,驱动程序可以直接访问用户地址空间。

在 SPARC 机器上,当内核模块试图直接访问用户地址空间时,系统会发生无法挽救的错误。必须确保驱动程序不会企图直接访问 SPARC 机器上的用户地址空间。


--------------------------------------------------------------------------------
警告-
x86 机器上运行的驱动程序可能无法在 SPARCA 机器上运行,因为 x86 的驱动程序可能会访问非法地址。


--------------------------------------------------------------------------------

不要直接访问用户数据。可以使用 ddi_copyin(9F) 和ddi_copyout(9F) 例程传送数据到用户地址空间或从用户地址空间获取数据。必须在 SPARC 机器的驱动程序中使用这两个例程来传输数据。如果在 x86 机器的驱动程序中使用这两个例程,那么可以非常轻松地将该驱动程序移植到 SPARC 机器上。修改存储在内核内存中的数据 一节展示了一个使用 ddi_copyin(9F) 和 ddi_copyout(9F) 的示例驱动程序。

mmap(2) 系统调用在进程地址空间和文件或共享的内存对象之间映射内存页面。为了响应 mmap(2) 系统调用,系统调用 devmap(9E) 入口点将设备内存映射到用户空间。然后该信息可以直接由用户应用程序访问。

设备驱动程序
设备驱动程序是管理设备与 OS 之间数据传输的可加载内核模块。可加载模块在引导时或通过请求进行加载,然后通过请求卸载内核。设备驱动程序是其他内核可以访问的 C 例程和数据结构的集合。这些例程必须使用称为入口点的标准接口。通过使用入口点,正在调用的模块保护了驱动程序的内部细节。请参阅 Writing Device Drivers 一书中的 Device Driver Entry Points 了解更多关于入口点的信息。

设备驱动程序在自己的 dev_ops(9S) 结构中声明它的通用入口点。驱动程序为 cb_ops(9S) 结构中与字符或数据块相关的例程声明入口点。对于大多数驱动程序通用的一些入口点和结构,显示在了下面的图中。

图 1-1 典型的设备驱动程序入口点
 

Solaris OS 提供了许多驱动程序入口点。在驱动程序中,不同类型的设备需要不同的入口点。下图展示了一些可用的入口点,它们根据驱动程序类型进行了分组。没有哪个单独的设备驱动程序会使用图中展示的所有入口点。

图 1-2 不同类型的驱动程序入口点
 

在 Solaris OS 中,驱动程序可以管理物理设备,例如磁盘设备,也可以管理软件设备(伪设备),例如总线连接设备或随机磁盘设备。对于硬件设备,设备驱动程序与管理该设备的硬件控制器进行通信。设备驱动程序使用户应用层无需接触具体设备的细节,这样应用级或系统调用就可以是通用或者设备独立的。

在以下情况中,需要访问驱动程序:

系统初始化。内核在系统初始化期间调用设备驱动程序,确定那些设备可用并初始化这些设备。

来自用户进程的系统调用。内核调用设备驱动程序执行该设备的 I/O 操作。例如 open(2)、read(2) 和 ioctl(2)。

用户级请求。内核调用设备驱动程序,服务来自命令的请求。例如 prtconf(1M)。

设备中断。内核调用设备驱动程序处理设备产生的中断。

总线复位。当总线复位时,内核调用设备驱动程序重新初始化驱动程序、设备或者两者。总线是 CPU 到设备的路径。

下图说明了设备驱动程序是如何与系统的其他部分进行交互的。

图 1-3 典型的设备驱动程序交互
 

驱动程序的目录组织结构
在 Solaris OS 中,设备驱动程序和其他内核模块按以下目录组织。请参阅 kernel(1M) 和 system(4) 手册页了解更多关于内核组织结构和如何将目录添加到内核模块搜索路径方面的信息。

/kernel
这些模块是绝大多数平台通用的。用来引导或者进行系统初始化的模块都属于这个目录。

/platform/`uname -i`/kernel
这些模块是专门针对可由 uname -i 命令识别的平台。

/platform/`uname -m`/kernel
这些模块是专门针对可由 uname -m 命令识别的平台。这些模块针对于硬件类,要比 uname -i 内核目录中的模块更加通用。

/usr/kernel
这些是用户模块。那些对于引导并不是必要的模块属于这个目录。本教程建议您将所有驱动程序放入 /usr/kernel 目录。

将这些驱动程序按不同目录组织的一大好处是,当您在以下例子的引导提示符中进行交互式引导时,可以有选择地加载启动时的不同组驱动程序。请参阅 boot(1M) 手册页了解更多信息。

 

Type    b [file-name] [boot-flags]       to boot with options
or      i                                to enter boot interpreter
or                                       to boot with defaults

                  <<< timeout in 5 seconds >>>

Select (b)oot or (i)nterpreter: b -a
bootpath: ,
Enter default directory for modules [/platform/i86pc/kernel /kernel
/usr/kernel]: /platform/i86pc/kernel /kernel

 

这个例子中, /usr/kernel 并不存在于用来搜索加载模块的目录列表当中。如果在 /usr/kernel 中,存在一个启动或连接期间导致内核发生严重错误的驱动程序,您或许会按照例子中的方法进行处理。取代忽略所有 /usr/kernel 中模块的更好方法是,将要测试的驱动程序放到他们自己的目录中。使用 moddir 内核变量将测试目录添加到内核模块搜索路径。在 kernel(1M) 和 system(4) 中描述了 moddir 内核变量。在临时位置安装驱动程序一节中描述了另一种用于处理可能存在启动问题的驱动程序的方法。

 

 
 
以上文章转自于 : http://developers.sun.com.cn/

阅读(386) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~