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

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-11 15:13:37


什么是内核?
第2 章• Solaris 内核和设备树51
DDI/DKI 允许您为运行Solaris 操作系统的任何计算机编写与平台无关的设备驱动程序。通
过这些二进制代码兼容的驱动程序,您可以更方便地将第三方硬件和软件集成到运行
Solaris 操作系统的任何计算机中。DDI/DKI 与体系结构无关,从而允许同一驱动程序在一
组不同的计算机体系结构中工作。
平台无关性是通过在以下方面设计DDI 实现的:
 动态装入和卸载模块
 电源管理
 中断处理
 从内核或用户进程访问设备空间,即寄存器映射和内存映射
 使用DMA服务次要设备访问内核或用户进程空间
 管理设备属性
设备树概述
Solaris OS 中的设备表示为互连的设备信息节点树。设备树描述特定计算机的已装入设备的
配置。
设备树组件
系统将会生成树结构,其中包含有关引导时连接到计算机的设备的信息。此外,系统正常
运行时也可以动态重新配置设备树。设备树从表示平台的根设备节点开始。
根节点下面是设备树的分支。分支由一个或多个总线结点设备和一个终止叶设备组成。
总线结点设备可为设备树中的从属设备提供总线映射和转换服务。PCI - PCI 网桥、
PCMCIA适配器和SCSI HBA都是结点设备的示例。编写结点设备驱动程序的讨论限于SCSI
HBA驱动程序的开发(请参见第17 章)。
叶设备通常为外围设备,如磁盘、磁带、网络适配器、图形卡缓存等。叶设备驱动程序可
以导出传统的字符驱动程序接口和块驱动程序接口。通过这些接口,用户进程可在存储设
备或通信设备中读取和写入数据。
系统通过以下步骤来生成树:
1. CPU 经过初始化后搜索固件。
2. 主要固件(OpenBoot、基本输入/输出系统(Basic Input/Output System, BIOS) 或
Bootconf)初始化并创建包含已知或自标识硬件的设备树。
3. 当主要固件在设备中发现兼容固件时,主要固件将初始化该设备并检索设备属性。
4. 该固件将查找并引导操作系统。
5. 内核从树的根节点开始,搜索匹配的设备驱动程序并将该驱动程序绑定到设备。
6. 如果设备是结点,则内核会查找固件尚未检测到的子设备。内核会将所有子设备都添加
到树的子树节点下面。
设备树概述
52 编写设备驱动程序• 2006 年11 月
7. 内核从步骤5 开始重复该过程,直到无需再创建设备节点。
每个驱动程序都会导出设备操作结构dev_ops(9S),以定义设备驱动程序可执行的操作。设
备操作结构包含通用操作(如attach(9E)、detach(9E) 和getinfo(9E))的函数指针。该结
构同时还包含了一组与特定总线结点驱动程序操作相关的函数指针,以及一组与特定叶结
点设备驱动程序操作相关的函数指针。
树结构将在节点之间创建父子关系。此父子关系是体系结构无关性的关键。当叶驱动程序
或总线结点驱动程序本质上需要依赖于体系结构的服务时,该驱动程序会请求其父级提供
该服务。采用此方法,不管计算机或处理器的体系结构是什么,驱动程序都可以正常运
行。下图显示了典型的设备树。
图2–2示例设备树
子树节点可以有一个或多个子节点。叶节点表示各个设备。
显示设备树
设备树可以采用以下三种方式显示:
 libdevinfo 库提供访问设备树内容的编程接口。
 prtconf(1M) 命令显示设备树的完整内容。
 /devices 分层结构是设备树的表示形式。使用ls(1) 命令查看该分层结构。
注– /devices 仅显示将驱动程序配置到系统中的设备。prtconf(1M) 命令将显示所有设备节
点,而不管系统中是否存在设备驱动程序。
设备树概述
第2 章• Solaris 内核和设备树53
libdevinfo 库
libdevinfo 库提供用于访问所有公共设备配置数据的接口。有关接口列表,请参见
libdevinfo(3LIB) 手册页。
prtconf 命令
以下摘录的prtconf(1M) 命令示例显示了系统中的所有设备。
System Configuration: Sun Microsystems sun4u
Memory size: 128 Megabytes
System Peripherals (Software Nodes):
SUNW,Ultra-5_10
packages (driver not attached)
terminal-emulator (driver not attached)
deblocker (driver not attached)
obp-tftp (driver not attached)
disk-label (driver not attached)
SUNW,builtin-drivers (driver not attached)
sun-keyboard (driver not attached)
ufs-file-system (driver not attached)
chosen (driver not attached)
openprom (driver not attached)
client-services (driver not attached)
options, instance #0
aliases (driver not attached)
memory (driver not attached)
virtual-memory (driver not attached)
设备树概述
54 编写设备驱动程序• 2006 年11 月
pci, instance #0
pci, instance #0
ebus, instance #0
auxio (driver not attached)
power, instance #0
SUNW,pll (driver not attached)
se, instance #0
su, instance #0
su, instance #1
ecpp (driver not attached)
fdthree, instance #0
eeprom (driver not attached)
flashprom (driver not attached)
SUNW,CS4231 (driver not attached)
network, instance #0
SUNW,m64B (driver not attached)
ide, instance #0
disk (driver not attached)
cdrom (driver not attached)
dad, instance #0
sd, instance #15
pci, instance #1
pci, instance #0
pci108e,1000 (driver not attached)
设备树概述
第2 章• Solaris 内核和设备树55
SUNW,hme, instance #1
SUNW,isptwo, instance #0
sd (driver not attached)
st (driver not attached)
sd, instance #0 (driver not attached)
sd, instance #1 (driver not attached)
sd, instance #2 (driver not attached)
[...]
SUNW,UltraSPARC-IIi (driver not attached)
SUNW,ffb, instance #0
pseudo, instance #0
/devices 目录
/devices 分层结构提供了表示设备树的名称空间。下面是/devices 名称空间的缩写列表。
样例输出对应于先前显示的示例设备树和prtconf(1M) 输出。
/devices
/devices/pseudo
/devices/pci@1f,0:devctl
/devices/SUNW,ffb@1e,0:ffb0
/devices/pci@1f,0
/devices/pci@1f,0/pci@1,1
/devices/pci@1f,0/pci@1,1/SUNW,m64B@2:m640
/devices/pci@1f,0/pci@1,1/ide@3:devctl
/devices/pci@1f,0/pci@1,1/ide@3:scsi
/devices/pci@1f,0/pci@1,1/ebus@1
设备树概述
56 编写设备驱动程序• 2006 年11 月
/devices/pci@1f,0/pci@1,1/ebus@1/power@14,724000:power_button
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:a
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:b
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:0,hdlc
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:1,hdlc
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:a,cu
/devices/pci@1f,0/pci@1,1/ebus@1/se@14,400000:b,cu
/devices/pci@1f,0/pci@1,1/ebus@1/ecpp@14,3043bc:ecpp0
/devices/pci@1f,0/pci@1,1/ebus@1/fdthree@14,3023f0:a
/devices/pci@1f,0/pci@1,1/ebus@1/fdthree@14,3023f0:a,raw
/devices/pci@1f,0/pci@1,1/ebus@1/SUNW,CS4231@14,200000:sound,audio
/devices/pci@1f,0/pci@1,1/ebus@1/SUNW,CS4231@14,200000:sound,audioctl
/devices/pci@1f,0/pci@1,1/ide@3
/devices/pci@1f,0/pci@1,1/ide@3/sd@2,0:a
/devices/pci@1f,0/pci@1,1/ide@3/sd@2,0:a,raw
/devices/pci@1f,0/pci@1,1/ide@3/dad@0,0:a
/devices/pci@1f,0/pci@1,1/ide@3/dad@0,0:a,raw
/devices/pci@1f,0/pci@1
/devices/pci@1f,0/pci@1/pci@2
/devices/pci@1f,0/pci@1/pci@2/SUNW,isptwo@4:devctl
/devices/pci@1f,0/pci@1/pci@2/SUNW,isptwo@4:scsi
将驱动程序绑定到设备
除了构造设备树之外,内核还可确定用于管理设备的驱动程序。
设备树概述
第2 章• Solaris 内核和设备树57
将驱动程序绑定到设备指的是系统选择用于管理特定设备的驱动程序的过程。绑定名称是
将驱动程序与设备信息树连接在一起的唯一设备节点名称。对于设备树中的每个设备,系
统都会尝试从已安装的驱动程序列表中选择一个驱动程序。
每个设备节点都有关联的name 属性。可以在系统引导期间通过外部代理(如PROM )或通
过driver.conf 配置文件指定此属性。无论在哪种情况下,name 属性都表示指定给设备树中
的设备的node name。node name 是在/devices 中可见并列在prtconf(1M) 输出中的名称。
图2–3设备节点名称
设备节点也可以有关联的compatible 属性。compatible 属性包含设备的一个或多个可能的驱
动程序名称或驱动程序别名的有序列表。
系统使用compatible 属性和name 属性来为设备选择驱动程序。如果compatible 属性存在,
则系统会首先尝试将compatible 属性的内容与系统中的驱动程序匹配。系统将从compatible
属性列表的第一个驱动程序名称开始,尝试将该驱动程序名称与系统中的已知驱动程序匹
配。系统将会处理该列表中的每一项,直到找到匹配项或者到达列表结尾。
如果name 属性或compatible 属性的内容与系统中的某个驱动程序匹配,则将该驱动程序绑
定到设备节点。如果未找到匹配项,则不会将任何驱动程序绑定到设备节点。
通用设备名称
某些设备将通用设备名称指定为name 属性的值。通用设备名称用于描述设备的功能,不实
际标识设备的特定驱动程序。例如,SCSI 主机总线适配器可能具有通用设备名称scsi。以
太网设备可能具有通用设备名称ethernet。
通过compatible 属性,系统可以确定具有通用设备名称的设备的备用驱动程序名称,例如,
glm 对应于scsi HBA设备驱动程序,hme 对应于ethernet 设备驱动程序。
具有通用设备名称的设备需要提供compatible 属性。
设备树概述
58 编写设备驱动程序• 2006 年11 月
注– 有关通用设备名称的完整说明,请参见IEEE 1275 Open Firmware Boot Standard。
下图显示了具有特定设备名称的设备节点。驱动程序绑定名称SUNW,ffb 与设备节点名称同
名。
binding name =
Device Node A
name = SUNW,ffb
/devices/SUNW,ffb@le,0:ffb0
SUNW,ffb
图2–4特定驱动程序节点绑定
下图显示了具有通用设备名称display 的设备节点。驱动程序绑定名称SUNW,ffb 是
compatible 属性驱动程序列表中与系统驱动程序列表中的驱动程序匹配的第一个名称。在这
种情况下,display 是图形卡缓存的通用设备名称。
compatible =
Device Node B
name = display
/devices/display@le,0:ffb0
fast_fb
SUNW,ffb
slow_fb
binding name = SUNW,ffb
图2–5通用驱动程序节点绑定
设备树概述
第2 章• Solaris 内核和设备树59
60
多线程
本章介绍Solaris 多线程内核的锁定原语和线程同步机制。设计设备驱动程序时应当充分利
用多线程的特性。本章提供了有关以下主题的信息:
 第61 页中的“锁定原语”
 第64 页中的“线程同步”
 第68 页中的“选择锁定方案”
锁定原语
在传统UNIX 系统中,每一部分内核代码都采用两种方法终止:通过显式调用sleep(1) 释放
CPU 资源或通过硬件中断。Solaris 操作系统的运行方式与此不同。系统可随时抢占内核线
程以运行其他线程。由于所有内核线程共享内核地址空间,并且通常需要读取和修改相同
的数据,因此内核提供了大量的锁定原语以防止线程损坏共享数据。这些机制包括互斥锁
(又称为mutex)、读取器/写入器锁以及信号量。
驱动程序数据的存储类
数据的存储类用于指示驱动程序是否需要采取显式步骤控制对数据的访问。共有三个数据
存储类:
 自动(栈)数据。每个线程有一个专用栈,因此驱动程序永远无需锁定自动变量。
 全局静态数据。全局静态数据可由驱动程序中任意数量的线程共享。驱动程序有时可能
需要锁定此类型的数据。
 内核堆数据。驱动程序中任意数量的线程均可共享内核堆数据,如kmem_alloc(9F) 分配
的数据。驱动程序需要随时保护共享数据。
互斥锁
互斥锁(mutex) 通常与一组数据关联,并控制对这些数据的访问。互斥锁提供了一种一次仅
允许一个线程访问这些数据的方法。互斥锁函数包括:
3第3 章
61
mutex_destroy(9F) 释放任何关联的存储空间。
mutex_enter(9F) 获取互斥锁。
mutex_exit(9F) 释放互斥锁。
mutex_init(9F) 初始化互斥锁。
mutex_owned(9F) 测试以确定当前线程是否持有互斥锁。仅限于在assert(9F) 中使
用。
mutex_tryenter(9F) 获取互斥锁(如果可用),但不阻塞。
设置互斥锁
设备驱动程序通常会为每个驱动程序数据结构分配一个互斥锁。互斥锁通常是设备驱动程
序中类型为kmutex_t 的字段。调用mutex_init(9F) 初始化要使用的互斥锁。通常在执行
attach(9E) 时为每个设备互斥锁进行此调用,在执行_init(9E) 时为全局驱动程序互斥锁进
行此调用。
例如,
struct xxstate *xsp;
...
mutex_init(&xsp->mu, NULL, MUTEX_DRIVER, NULL);
...
有关互斥锁初始化的较完整示例,请参见第6 章。
驱动程序在卸载之前必须使用mutex_destroy(9F) 销毁互斥锁。通常在执行detach(9E) 时为
每个设备互斥锁进行销毁操作,在执行_fini(9E) 时为全局驱动程序互斥锁进行销毁操作。
使用互斥锁
驱动程序如果需要读写共享数据结构,必须执行以下操作:
 获取互斥锁
 访问数据
 释放互斥锁
互斥锁的作用域(即互斥锁保护的数据)完全由程序员决定。仅当访问数据结构的每个代
码路径都保护数据结构并且同时持有互斥锁时,互斥锁才会保护该数据结构。
锁定原语
62 编写设备驱动程序• 2006 年11 月
读取器/写入器锁
读取器/写入器锁可控制对数据集的访问。读取器/写入器锁之所以这样命名,是由于许多线
程可同时持有读锁,但仅有一个线程可持有写锁。
大多数设备驱动程序不使用读取器/写入器锁。这些锁的速度比互斥锁要慢。这些锁仅当保
护通常进行读取但不经常写入的数据时才会提高性能。在此情况下,对互斥锁的争用可能
会成为一个瓶颈,因此使用读取器/写入器锁效率可能更高。下表概述了读取器/写入器函
数。有关详细信息,请参见rwlock(9F) 手册页。读取器/写入器锁函数包括:
rw_destroy(9F) 销毁读取器/写入器锁
rw_downgrade(9F) 将读取器/写入器锁的持有者从写入器降级为读取器
rw_enter(9F) 获取读取器/写入器锁
rw_exit(9F) 释放读取器/写入器锁
rw_init(9F) 初始化读取器/写入器锁
rw_read_locked(9F) 确定是否持有用于读/写操作的读取器/写入器锁
rw_tryenter(9F) 尝试在无需等待的情况下获取读取器/写入器锁
rw_tryupgrade(9F) 尝试将读取器/写入器锁的持有者从读取器升级为写入器
信号
计数信号量可用作管理设备驱动程序中线程的替代原语。有关更多信息,请参见
semaphore(9F) 手册页。信号函数包括:
sema_destroy(9F) 销毁信号。
sema_init(9F) 初始化信号。
sema_p(9F) 减小信号,可能会阻塞。
sema_p_sig(9F) 减小信号,但不会阻塞(如果信号处于待处理状态)。请参见第69
页中的“线程无法接收信号”。
sema_tryp(9F) 尝试减小信号,但不阻塞。
sema_v(9F) 增加信号,可能会解除阻塞等待者。
 

以上文章转自于 : http://developers.sun.com.cn/
阅读(582) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~