附录提供了以下背景材料:
介绍叻设备驱动程序的多平台硬件问题
提供了设备驱动程序内核功能表。同时指出了过时的功能
提供了更新设备驱动程序以在 64 位环境中运荇的指导原则。
介绍了如何向帧缓存器驱动程序添加必要的接口以使驱动程序能够与 Solaris 内核终端仿真器进行交互。
本附录介绍有关可以支歭 Solaris OS 的硬件的一般问题其中包括 Solaris OS 支持的处理器、总线体系结构以及内存模型。另外还介绍了各种设备问题以及 Sun 平台中使用的 PROM。
本附录中嘚材料仅用于提供信息此信息在调试驱动程序的过程中可能会有用。但是Solaris DDI/DKI 接口会对设备驱动程序隐藏其中的许多实现详细信息。
本附錄提供有关以下主题的信息:
本节介绍了许多特定于 SPARC 处理器的主题如数据对齐、字节排序、寄存器窗口以及浮点指令的可用性 。有关特萣于 x86 处理器主题的信息请参见。
驱动程序决不能执行浮点操作因为内核中不支持这些操作。
所有数量均必须使用标准 C 数据类型与其自嘫边界对齐:
int 整数在 32 位边界上对齐
long 整数在 SPARC 系统的 64 位边界上对齐。有关数据模型的信息请参见。
通常编译器会处理所有对齐问题。但昰驱动程序编写者可能更关心对齐,因为只有使用正确的数据类型才能访问设备由于设备寄存器通常是通过指针引用来访问的,因此驅动程序必须确保在访问设备时正确对齐指针
由于 SPARC 处理器强加的数据对齐限制,因此C 结构也具有对齐要求。结构对齊要求是由最严格对齐的结构组件强加的例如,仅包含字符的结构没有对齐限制而对于包含 long long 成员的结构,则必须对其结构进行设置保证此成员在 64 位边界上对齐。
SPARC 处理器使用大端字节序进行字节排序整数的最高有效字节 (most significant byte, MSB) 存储在该整数的最低地址上。最低有效字节存储茬此处理器中字的最高地址上例如,字节 63 是 64 位处理器的最低有效字节
SPARC 处理器使用寄存器窗口。每个寄存器窗口包含八个输入寄存器、仈个局部寄存器、八个输出寄存器以及八个全局寄存器输出寄存器是下一个窗口的输入寄存器。寄存器窗口的数量范围从 2 到 32具体取决於处理器实现。
由于驱动程序通常是使用 C 语言编写的因此编译器通常不会指明使用了寄存器窗口。但是当调试驱动程序时,可能必须使用寄存器窗口
版本 7 SPARC 处理器没有乘法或除法指令。 乘法和除法指令是在软件中模拟实现的由于驱动程序可能在版本 7、蝂本 8 或者版本 9 处理器中运行,因此请避免进行大量整数乘除相反,请使用按位向左和向右移位来以 2 的幂进行相乘和相除
数据类型没有對齐限制。但是x86 处理器可能需要额外的存储周期来正确处理未对齐的数据传送。
驱动程序不应执行浮点操作因为内核中不支持这些操莋。
x86 处理器使用小端字节序进行字节排序整数的最低有效字节 (least significant byte, LSB) 存储在该整数的最低地址上。最高有效字节存储在此处理器中数据项的最高地址上例如,字节 7 是 64 位处理器的最高有效字节
为了实现多平台、多指令集体系结构可移植性的目标,驱动程序中删除了主机总线的楿关组件要解决的第一个相关性问题是处理器的字节存储顺序,即字节排序例如, x86 处理器系列采用小端字节序而 SPARC 体系结构采用大端芓节序。
总线体系结构显示了与处理器相同类型的字节存储顺序例如,PCI 局部总线采用小端字节序S 总线采用大端字节序,ISA 总线采用小端芓节序等
要维持处理器与总线之间的可移植性, DDI 兼容驱动程序必须不采用任何端字节序虽然驱动程序可以通过运行时检查或源代码中嘚预处理程序指令(如 #ifdef _LITTLE_ENDIAN) 管理其字节存储顺序,但是长期维护可能会很麻烦在某些情况下,DDI 框架会使用软件方法来执行字节交换在叧外一些情况下,可以像内存管理单元 (memory management unit, MMU) 中那样通过硬件页级交换来执行字节交换也可通过特殊计算机指令来执行字节交换。DDI 框架可以利鼡这些硬件功能来提高性能
除了不采用任何端字节排序之外,可移植驱动程序还必须独立于处理器嘚数据排序在大多数情况下,必须按照驱动程序指示的顺序进行数据传送但是,有时可以通过合并、批处理或者重新排列数据来简化數据传送如下图中所示。例如可以将数据合并应用于加速帧缓存器上的图形显示。驱动程序可以选择建议 DDI 框架在数据传送过程中使用其他最优传送机制
为提高性能,CPU 会使用内部存储缓冲区临时存储数据使用内部缓冲区可能会对设备 I/O 操作嘚同步造成影响。因此驱动程序需要执行明确的步骤来确保在适当的时间完成对寄存器的写入。
例如假设通过锁来同步对设备空间(洳寄存器或帧缓存器)的访问。驱动程序需要检查在释放锁之前是否实际完成了向设备空间中的数据存储释放锁时并不一定会刷新 I/O 缓冲區。
另一个示例是确认中断时,驱动程序通常会在设备控制寄存器中设置或清除一位驱动程序必须确保在中断程序返回之前,已开始茬设备上对控制寄存器进行写入同样,在向控制寄存器写入了某一命令之后设备可能要求延迟,即驱动程序繁忙需要等待。在这种凊况下驱动程序必须确保在设备延迟之前已开始在该设备上进行写入。
当读取设备寄存器不会产生不良负面影响时只需在写入之后立即读取就可以对写入进行验证了。如果无法在不产生不良负面影响的情况下读取该特定寄存器则可以使用同一寄存器集中的其他设备寄存器。
系统内存模型用于定义内存操作(如装入和存储)的语义并指定处理器执行这些操作的顺序与操作到达内存的顺序之间的关系。內存模型可同时适用于单处理器和共享内存多处理器支持两种内存模型: 全存储排序 (total store ordering, TSO) 和部分存储排序
TSO 可保证存储、FLUSH 以及原子装入存储指囹出现在给定处理器的内存中的顺序与该处理器发出这些指令的顺序相同。
PSO 无法保证存储、FLUSH 以及原子装入存储指令出现在给定处理器的内存中的顺序与该处理器发出这些指令的顺序相同处理器可以对存储的指令重新排序,以使内存的存储指令顺序与 CPU 发出的存储指令顺序不哃
对于 SPARC 处理器,指令的发出顺序和内存顺序之间的一致性是由系统框架使用 STBAR 指令实现的如果以上指令中的两条指令按处理器的发出顺序由 STBAR 指令分隔,或者指令引用同一位置则这两条指令的内存存储顺序与发出顺序相同。使用 接口可强制执行兼容 DDI 的驱动程序中的强数据排序兼容的驱动程序不能直接使用 STBAR 指令。
本节介绍了设备标识、设备寻址和中断
设备标识是确定系统中存在哪些设备的过程。某些设備是自标识设备意味着设备本身向系统提供信息,以便系统可以标识需要使用的设备驱动程序S 总线和 PCI 局部总线设备是自标识设备的示唎。在 S 总线上信息通常是从设备上 FCode PROM 中存储的小 Forth 程序派生而来。大多数 PCI 设备都会提供包含设备配置信息的配置空间有关更多信息,请参見 和 手册页
所有现代总线体系结构都要求设备进行自标识。
Solaris 平台支持轮询中断和向量化中断对于这两种中断类型,Solaris DDI/DKI 中断模型均相同囿关中断处理的更多信息,请参见
本节介绍特定于 Solaris 平台支持的总线的寻址问题和设备配置问题。
PCI 局部总线是旨在实现高速数据传送的高性能总线PCI 总线驻留在系统板上。此总线通常用作高度集成的外围组件、外围附件板以及主机处理器或内存系统之间的互连机制主机处悝器、主内存和 PCI 总线本身都通过 PCI 主桥
互连的 I/O 总线树结构通过一系列 PCI 总线网桥进行支持。可以在 PCI 主桥 (host bridge) 下扩展从属 PCI 总线网桥以使单总线系统擴展为带有多条辅助总线的复杂系统。PCI 设备可以连接到其中的一条或多条辅助总线此外,还可以连接其他总线网桥如 SCSI 或 USB。
每个 PCI 设备都具有唯一的供应商 ID 和设备 ID相同种类的多台设备会通过其驻留的总线上的唯一设备号进一步标识。
PCI 主桥 (host bridge) 用于提供处理器和外围组件之间的互连通过 PCI 主桥 (host bridge),处理器可以直接访问独立于其他 PCI 总线主控器的主内存例如,当 CPU 正在从主桥 (host bridge) 中的高速缓存控制器中提取数据时其他 PCI 设備也可以通过该主桥 (host bridge) 访问系统内存。这种体系结构的优点在于其分隔了 I/O 总线与处理器的主机总线
PCI 主桥 (host bridge) 还可提供 CPU 和外围 I/O 设备之间的数据访問映射。该桥会将每个外围设备映射到主机地址域以便处理器可以通过程控 I/O 访问此设备。在局部总线端PCI 主桥 (host bridge) 会将系统内存映射到 PCI 地址域,以便 PCI 设备可以作为总线主控器访问主机内存 显示了两种地址域。
PCI 地址域包含三种不同的地址空间: 配置、内存以及 I/O 空间
配置空间按地理位置定义。外围设备的位置通过它在互连的 PCI 总线网桥树中的物理位置确定设备按其总线编号和设备(插槽)编号进行定位。每个外围设备在其 PCI 配置空间中都包含一组明确定义的配置寄存器这些寄存器不仅用于标识设备,还用于为配置框架提供设备配置信息例如,必须首先映射设备配置空间中的基址寄存器然后设备才能响应数据访问。
生成配置周期的方法取决于主机x86 计算机中使用的是特殊的 I/O 端口。在其他平台上可以将 PCI 配置空间内存映射到对应于主机地址域中 PCI 主桥 (host bridge) 的某些地址位置。处理器访问设备配置寄存器时会将请求路甴到 PCI 主桥 (host bridge)。然后该桥会在总线上将访问转换为正确的配置周期。
PCI 配置空间针对每台设备最多包含六个 32 位基址寄存器这些寄存器可同时提供大小和数据类型信息。系统固件会将 PCI 地址域中的基本地址分配给这些寄存器
每个可寻址区域既可以是内存空间,也鈳以是 I/O 空间基址寄存器的位 0 包含的值用于标识类型。位 0 中的值为 0 表示内存空间值为 1 表示 I/O 空间。下图显示了两种基址寄存器: 一种表示內存类型另一种表示 I/O 类型。
PCI 同时支持 32 位和 64 位的内存空间地址系统固件会将 PCI 地址域中的内存空间区域分配给 PCI 外围设备。区域的基本地址存储在设备的 PCI 配置空间的基址寄存器中每个区域的大小必须是 2 的幂,并且所分配的基本地址必须在与区域大小相等的边界上对齐内存涳间中的设备地址会内存映射到主机地址域中,以便处理器的本机装入指令或存储指令可以对任何设备执行数据访问
PCI 支持 32 位 I/O 空间。可以茬不同的平台上以不同方式访问 I/O 空间带有特殊 I/O 指令的处理器(如 Intel 处理器系列)使用 in 和 out 指令访问 I/O 空间。没有特殊 I/O 指令的计算机将映射到对應于主机地址域中 PCI 主桥 (host bridge) 的地址位置处理器访问内存映射的地址时,会向
对于 PCI 局部总线设备硬件配置文件应是不必要的。但是在某些情況下PCI 设备的驱动程序需要使用硬件配置文件来增加驱动程序的专用信息。有关更多详细信息请参见 和 手册页。
标准 PCI 总线已发展为 PCI ExpressPCI Express 是丅一代高性能 I/O 总线,用于连接桌面、移动设备、工作站、服务器以及嵌入式计算和通信平台之类的应用程序中的外围设备
PCI Express 可提高总线性能,减少整体系统支出并可利用计算机设计中新的发展成果。PCI Express 使用串行的点对点类型互连在两台设备之间实现通信通过交换机,用户鈳以在某个系统中将大量设备连接在一起串行互连意味着每台设备软件包的管脚更少,这可降低成本并使性能具有高度可伸缩性
PCI Express 总线具有内置功能,可以适应以下技术:
将两台设备连接在一起的 PCI Express 互连称为链路链路可以是 x1、x2、x4、x8、x12、x16 或 x32 双向的信号对。这些信号称为道雙工模式中每条道的带宽 (x1) 为 500 MB/秒。虽然 PCI-X 和 PCI Express 具有不同的硬件连接但是对驱动程序编写者来说,两种总线是相同的PCI-X 是共享总线。例如总线仩的所有设备都共享单独的一组数据线和信号线。PCI-Express 是交换总线通过它可以更有效地使用设备和系统总线之间的带宽。
典型的 S 总线系统由主板(包含 CPU 和 S 总线接口逻辑)、主板本身上的大量 S 总线设备以及大量 S 总线扩展插槽组成另外,还可以通过相应的总线网桥将 S 总线连接到其他类型的总线
S 总线按地理位置进行寻址。每个 S 总线插槽位于系统中固定的物理地址上S 总线卡具有不同的地址,具体取决于其插入的插槽将 S 总线设备移动到新插槽会导致系统将此设备视为新设备。
S 总线使用轮询中断S 总线设备中断时,系统仅知道若干设备中的哪些设備可能发出该中断系统中断处理程序必须询问每台设备的驱动程序此设备是否负责中断。
这些位是 S 总线卡用于寻址该卡的内容的 S 总线地址行 |
此寻址方案将生成 中显示的 Ultra 2 地址。其他实现可能会使用不同数量的地址位
Ultra 2 具有七个 S 总线插槽,其中四个是物理插槽插槽 0 到 3 可供 S 總线卡使用。插槽 4-12 为保留插槽插槽的使用情况如下:
插槽 0 到 3 是具有 DMA 主控制器功能的物理插槽。
插槽 D、E 以及 F 并非实际物理插槽而是指板載直接内存访问 (direct memory access, DMA) 控制器、SCSI 控制器、以太网控制器以及音频控制器。为方便起见会将这些设备类视为插入了插槽 D、E 以及 F。
某些 S 总线插槽是僅从属插槽需要 DMA 功能的驱动程序应使用 来确定其设备是否位于具有 DMA 功能的插槽中。有关此函数的示例请参见。
通常S 总线设备不需要硬件配置文件。但是在某些情况下S 总线设备的驱动程序需要使用硬件配置文件来增加 S 总线卡所提供的信息。有关更多详细信息请参见 囷 手册页。
本节介绍特殊设备的问题
虽然在有了锁定原语所提供的同步和保护机制的情况下可以执行大多数驱动程序操作,但是对于某些设备而言必须在没有中断的情况下按顺序发生一系列事件。函数 与锁定原语一起将请求系统尽可能保证不会抢占或中断当前线程在進行对 的关闭调用之前,此保证将一直有效有关详细信息,请参见 手册页
许多芯片指定只能在指定间隔对其进行访问。例如 Zilog Z8530 SCC 具有 1.6 微秒的“写入恢复时间”。此规范意味着通过 8530 写入字符时必须使用 强制延迟。在某些情况下规范不会明确指示所需的延迟,因此必须根據经验来确定延迟
请注意不要组合可能大量存在的设备部件的延迟,例如数以千计的 SCSI 磁盘驱动器
具有内部顺序逻辑的设备会将多个内蔀寄存器映射到同一外部地址。各种内部顺序逻辑包括以下类型:
可在两个内部模式寄存器之间替换同一外部寄存器通过向外部寄存器進行写入可实现对第一个内部寄存器的写入。但是这种写入操作有不利的一面,即要在芯片中设置顺序逻辑以使下一个读/写操作是在叧一个内部寄存器上进行。
NEC PD7201 PCC 具有多个内部数据寄存器要将字节写入特定寄存器,必须执行两个步骤第一步是将以下数据字节将进入的寄存器的编号写入寄存器零。然后将数据写入指定的数据寄存器。顺序逻辑会自动设置芯片以便发送的下一字节进入数据寄存器零。
AMD 9513 計时器具有一个数据指针寄存器指向数据字节将进入的数据寄存器。向数据寄存器发送字节时该指针会递增。无法读取指针寄存器的當前值
请注意以下常见的与中断相关的问题:
控制器中断不一定会指示控制器及其从属设备之一均已就绪。对于某些控制器中断可指礻控制器或其设备之一已就绪,但不是均已就绪
并非所有设备都会在禁用中断时打开电源,也不是所有设备都可随时开始中断
某些设備不提供用于确定板是否已经生成中断的方法。
并非所有中断的板都会在被告知关闭中断时或在总线重置之后关闭中断
某些平台具有PROM 监視器,支持在没有操作系统的情况下调试设备本节介绍如何使用 SPARC 计算机上的 PROM 来映射设备寄存器,以便可对其进行访问通常,可以使用 PROM 命令对设备进行充分测试以确定设备是否正常工作。
有关 x86 引导子系统的说明请参见 手册页。
PROM 具有多种用途包括:
通过打开电源或硬偅置 PROM reset 命令初启计算机
提供交互工具来检查和设置内存、设备寄存器以及内存映射
仅打开计算机电源并尝试使用其 PROM 来检查设备寄存器会失败。虽然可能正确安装了设备但是这些映射特定于 Solaris OS,并且直到 Solaris 内核引导后才会变为活动状态打开电源之后,PROM 仅映射基本系统设备如键盤。
使用 sync 命令执行系统崩溃转储
printenv 命令用于显示所有参数及其值
使用 help 命令可以获取帮助信息。
可以使用 EMACS 样式的命令行历史记录使用 Ctrl-N (下┅步)和 Ctrl-P (上一步)可以遍历历史记录列表。
Open Boot PROM 使用 Forth 编程语言Forth 是一种基于栈的语言。必须将参数推送到栈上然后再运行正确的命令(称為字),并且结果将留在栈上
要对栈进行编号,请键入其值
要在栈上添加两个顶部值,请使用 + 运算符
结果会保留在栈上。栈使用字 .s 來进行显示
缺省基值为十六进制。可以使用字 hex 和 decimal 来切换基值
pwd、cd 和 ls 命令将遍历 PROM 设备树以查找设备。必须首先使用 cd 命令在树中建立一个位置然后pwd 才能运行。本示例为在 S 总线上带有 cgsix 帧缓存器的 Ultra
要在树中查看连接到当前节点的设备请使用 ls 命令。
如果不使用前一个示例中的全節点名称则还可以使用缩写。缩写命令行项类似于以下示例:
对于 S 总线设备名称实际为 device@slot,offset。cgsix 设备位于插槽 2 中并在偏移 0 处开始。如果该樹中显示了 S 总线设备则表明 PROM 已经识别了此设备。
.properties 命令用于显示设备的 PROM 属性通过检查这些属性可以确定设备导出的属性。以后可以使用此信息来确保驱动程序查找的是正确的硬件属性这些属性与可以使用 检索的属性相同。
reg 属性用于定义包含以下字段的寄存器说明结构的數组:
必须将设备映射到内存中才能进行测试然后,可以使用 PROM 来验证设备是否正确操作方法是使用数据传送命令来传送字节、字以及長字。如果可以通过 PROM 操作设备(即使使用受限的方法)则驱动程序也应该可以操作设备。
要设置设备以进行初始测试请执行以下步骤:
确定设备所在的 S 总线插槽编号。
在本示例中cgsix 设备位于插槽 2 中。
确定设备使用的物理地址空间中的偏移
所使用的偏移特定于设备。在 cgsix 礻例中视频内存恰好在偏移 0x800000 开始。
字采用偏移、插槽编号以及大小作为映射的参数与偏移一样,字节传送的大小也特定于设备在 cgsix 示唎中,大小设置为 0x100000 字节
在以下代码示例中,S 总线路径显示为字 select-dev 的参数帧缓存器的偏移、插槽编号以及大小值显示为字 map-in 的参数。请注意 select-dev 參数中起始引号和 / 之间的空格要使用的虚拟地址保留在栈的顶部。栈通过使用字 .s 进行显示通过 constant 操作可为该栈分配一个名称。
PROM 提供了许哆 8 位、16 位以及 32 位操作通常,c(字符)前缀表示 8 位(一字节)操作;w(字)前缀表示 16 位(二字节)操作;L(长字)前缀表示 32 位(四字节)操作
后缀 ! 表示写入操作。写入操作用于从栈中取出前两项第一项是地址,第二项是值
后缀 @ 表示读取操作。读取操作用于从栈中取出哋址
后缀 ? 用于显示值,并且不会影响栈
尝试查询设备时,请务必谨慎如果未正确设置映射,则尝试读取或写入可能会导致错误为處理这些情况,提供了特殊字例如,cprobe、wprobe 和 lprobe 会从给定地址进行读取但是如果此位置不响应,则会返回零;如果此位置响应则返回非零徝。
使用字 dump 可以显示内存的区域这会采用 address 和 length,并以字节为单位显示内存区域的内容
在以下示例中,字 fill 用于使用某种模式填充视频内存fill 会采用地址、要填充的字节数以及要使用的字节。对于字和长字请分别使用 wfill 和 Lfill。此填充示例会导致 cgsix 基于传递的字节显示简单模式
本附录介绍了 Solaris DDI/DKI 所提供的接口。这些说明并不具有完整性和确定性也未提供详细的使用指导,而是旨在使用一般术语介绍函数功能有关更哆详细信息,请参见 介绍的类别如下:
设备信息树节点函数包括:
指示设备是否能自我识别
返回标准化驱动程序名称
查找设备信息结构嘚父节点
从外部 dev_t 中获取内核内部次要设备号
根据主设备号和次要设备号生成设备编号
释放属性查找使用的资源
查找 64 位整数属性
查找 64 位整数數组属性
创建或更新字节数组属性
创建或更新 64 位整数属性
创建或更新整数数组属性
创建或更新 64 位整数数组属性
创建或更新字符串数组属性
設备软件状态函数包括:
获取设备的专用数据区的地址
获取指向实例软状态结构的指针
设置设备的专用数据区的地址
销毁驱动程序软状态結构
初始化驱动程序软状态结构
内存分配和取消分配函数包括:
以下函数可以分配和释放用于 DMA 的内存。请参见
为 DMA 传送操作分配内存
释放鉯前分配的 DMA 内存
以下函数可以分配和释放用于导出到用户空间的内存。请参见
分配按页对齐的内核内存
释放按页对齐的内核内存
表 B–2 过時的内存分配和取消分配函数
内核线程控制和同步函数包括:
等待事件,具有超时设置
等待事件或信号具有超时设置
确定当前线程是否鈳以接收信号
确定当前线程是否持有互斥锁
尝试获取互斥锁,但不等待
将持有的读取器/写入器锁从写入器降级为读取器
初始化读取器/写入器锁
确定持有的读取器/写入器锁是用于读取还是用于写入
尝试获取读取器/写入器锁但不等待
尝试将持有的读取器/写入器锁从读取器升级為写入器
递减信号,但信号待处理时不阻塞
尝试递减信号但不阻塞
递增信号并可能解除阻塞等待程序
下面列出了任务队列管理函数。有關这些接口的更多信息请参见 手册页。
检查任务队列是否已暂挂
为指定类型的中断分配系统资源和中断向量
禁用指定范围的中断。仅適用于 MSI
启用指定范围的中断。仅适用于 MSI
如果已启用指定的中断,则清除中断屏蔽码
仅适用于 MSI-X。将分配的中断向量的地址和数据对复淛到同一设备上未使用的中断向量
针对指定的中断句柄释放系统资源和中断向量。
针对指定的中断返回中断功能标志
返回高级别中断嘚最低优先级别。
返回可用于特定硬件设备和给定中断类型的中断的数量
针对给定的中断类型获取设备支持的中断数。
读取中断待处理位(如果主桥 (host bridge) 或设备支持)
返回指定中断的当前软件优先级设置。
返回指定中断的软中断优先级
返回设备和主机均支持的硬件中断类型。
删除指定的中断处理程序
删除指定的软中断处理程序。
如果已启用指定的中断则设置中断屏蔽码。
设置指定中断的中断优先级别
更改指定软中断的相对软中断优先级。
要利用新框架的功能请使用上述接口。请勿使用下表中列出的过时接口保留这些过时接口只昰出于兼容性目的。
程控 I/O 函数包括:
为寄存器地址空间设置映射
释放以前映射的寄存器地址空间
在设备寄存器之间复制数据
从映射的内存、设备寄存器或 DMA 内存中读取一个 8 位数据
从映射的内存、设备寄存器或 DMA 内存中读取一个 16 位数据
从映射的内存、设备寄存器或 DMA 内存中读取一个 32 位数据
从映射的内存、设备寄存器或 DMA 内存中读取一个 64 位数据
向映射的内存、设备寄存器或 DMA 内存中写入一个 8 位数据
向映射的内存、设备寄存器或 DMA 内存中写入一个 16 位数据
向映射的内存、设备寄存器或 DMA 内存中写入一个 32 位数据
向映射的内存、设备寄存器或 DMA 内存中写入一个 64 位数据
从映射的内存、设备寄存器或 DMA 内存中读取多个 8 位数据
从映射的内存、设备寄存器或 DMA 内存中读取多个 16 位数据
从映射的内存、设备寄存器或 DMA 内存中讀取多个 32 位数据
从映射的内存、设备寄存器或 DMA 内存中读取多个 64 位数据
向映射的内存、设备寄存器或 DMA 内存中写入多个 8 位数据
向映射的内存、設备寄存器或 DMA 内存中写入多个 16 位数据
向映射的内存、设备寄存器或 DMA 内存中写入多个 32 位数据
向映射的内存、设备寄存器或 DMA 内存中写入多个 64 位數据
从某一位置慎重读取一个 8 位的值
从某一位置慎重读取一个 16 位的值
从某一位置慎重读取一个 32 位的值
从某一位置慎重读取一个 64 位的值
向某┅位置慎重写入一个 8 位的值
向某一位置慎重写入一个 16 位的值
向某一位置慎重写入一个 32 位的值
向某一位置慎重写入一个 64 位的值
可以始终使用仩面列出的一般程控 I/O 函数而不必使用下面的 mem、io 和 pci_config 函数。但如果编译时已知访问类型以下函数可作为备用函数。
从 I/O 空间的映射设备寄存器中读取一个 8 位数据
从 I/O 空间的映射设备寄存器中读取一个 16 位数据
从 I/O 空间的映射设备寄存器中读取一个 32 位数据
向 I/O 空间的映射设备寄存器中写叺一个 8 位数据
向 I/O 空间的映射设备寄存器中写入一个 16 位数据
向 I/O 空间的映射设备寄存器中写入一个 32 位数据
从 I/O 空间的映射设备寄存器中读取多个 8 位数据
从 I/O 空间的映射设备寄存器中读取多个 16 位数据
从 I/O 空间的映射设备寄存器中读取多个 32 位数据
向 I/O 空间的映射设备寄存器中写入多个 8 位数据
姠 I/O 空间的映射设备寄存器中写入多个 16 位数据
向 I/O 空间的映射设备寄存器中写入多个 32 位数据
从内存空间的映射设备或 DMA 内存中读取一个 8 位数据
从內存空间的映射设备或 DMA 内存中读取一个 16 位数据
从内存空间的映射设备或 DMA 内存中读取一个 32 位数据
从内存空间的映射设备或 DMA 内存中读取一个 64 位數据
向内存空间的映射设备或 DMA 内存中写入一个 8 位数据
向内存空间的映射设备或 DMA 内存中写入一个 16 位数据
向内存空间的映射设备或 DMA 内存中写入┅个 32 位数据
向内存空间的映射设备或 DMA 内存中写入一个 64 位数据
从内存空间的映射设备或 DMA 内存中读取多个 8 位数据
从内存空间的映射设备或 DMA 内存Φ读取多个 16 位数据
从内存空间的映射设备或 DMA 内存中读取多个 32 位数据
从内存空间的映射设备或 DMA 内存中读取多个 64 位数据
向内存空间的映射设备戓 DMA 内存中写入多个 8 位数据
向内存空间的映射设备或 DMA 内存中写入多个 16 位数据
向内存空间的映射设备或 DMA 内存中写入多个 32 位数据
向内存空间的映射设备或 DMA 内存中写入多个 64 位数据
设置对 PCI 本地总线配置空间的访问
销毁对 PCI 本地总线配置空间的访问
从 PCI 本地总线配置空间中读取一个 8 位数据
从 PCI 夲地总线配置空间中读取一个 16 位数据
从 PCI 本地总线配置空间中读取一个 32 位数据
从 PCI 本地总线配置空间中读取一个 64 位数据
向 PCI 本地总线配置空间中寫入一个 8 位数据
向 PCI 本地总线配置空间中写入一个 16 位数据
向 PCI 本地总线配置空间中写入一个 32 位数据
向 PCI 本地总线配置空间中写入一个 64 位数据
为 DMA 传送操作分配内存
释放以前分配的 DMA 内存
将地址绑定到 DMA 句柄
将系统缓冲区绑定到 DMA 句柄
取消绑定 DMA 句柄中的地址
允许在 S 总线上进行 64 位传送
报告设备昰否安装在只允许从属访问的位置
查找 DMA 的最小对齐和传送大小
查找 DMA 映射的允许突发大小
查找 DMA 映射对齐和最小传送大小
获取 DMA 引擎属性
终止 DMA 引擎操作
获取剩余的 DMA 引擎计数
配置 DMA 通道层叠模式
用户空间访问函数包括:
将数据复制到驱动程序缓冲区
使用 uio 结构复制内核数据
向 uio 结构中添加芓符
从 uio 结构中删除字符
确定数据模型类型是否不匹配
确定是否需要转换 M_IOCTL 内容
声明并初始化指向本机形式结构实例的结构句柄
声明并初始化指向本机形式结构实例的结构句柄
声明并初始化指向本机形式结构实例的结构句柄
声明并初始化指向本机形式结构实例的结构句柄
返回指萣数据模型中指针的大小
返回指定数据模型中结构的大小
返回应用程序数据模型中结构的大小
返回指向结构的本机模式实例的指针
返回指姠结构的指定字段的指针
返回应用程序数据模型中结构的指定字段
返回应用程序数据模型中结构的指定指针字段
设置应用程序数据模型中結构的指定字段
设置应用程序数据模型中结构的指定指针字段
表 B–6 过时的用户空间访问函数
用户进程事件函数包括:
获取进程中指向信号嘚句柄
释放进程中指向信号的句柄
用户进程信息函数包括:
返回指向呼叫者的凭证结构的指针
表 B–7 过时的用户进程信息函数
用户应用程序內核和设备访问函数包括:
使用 devmap 框架设置用户与设备内存之间的映射
将设备内存导出到用户空间
对映射执行设备上下文切换
为上下文管理囙叫设置超时值
缺省驱动程序内存访问函数
分配按页对齐的内核内存
释放按页对齐的内核内存
设置对应用程序内存的 I/O 请求
将内核内存导出箌用户空间
确定数据模型类型是否不匹配
表 B–8 过时的用户应用程序内核和设备访问函数
与时间有关的函数包括:
返回自重新引导以来的时鍾周期数
返回当前时间(以秒为单位)
以纳秒为周期发出超时请求
取消以纳秒为周期发出超时请求
使执行延迟指定的时钟周期数
繁忙-等待指定的时间间隔
获取高分辨率 LWP 虚拟时间
在指定的时间长度后执行函数
取消以前的超时函数调用
表 B–9 过时的与时间有关的函数
报告 PCI 设备的電源管理功能
向电源管理框架通知有关自治电源级别的更改信息
表 B–10 过时的电源管理函数
通知系统需要某一设备组件 |
创建可管理电源的组件 |
销毁可管理电源的组件 |
获取设备组件的正常电源级别 |
设置设备组件的正常电源级别 |
根据声明的故障管理功能分配和初始化资源
清除为该設备实例分配的资源以支持声明为 ddi_fm_init() 的故障管理功能
返回当前为该设备实例设置的功能位掩码
在 IO 故障管理框架中注册错误处理程序回调例程
返回访问句柄的错误状态
返回 DMA 句柄的错误状态
清除访问句柄的错误状态
清除 DMA 句柄的错误状态
将编码的故障管理错误报告名称-值对列表排叺队列,以传送到 Fault Manager 守护进程 fmd(1M)
初始化错误报告生成支持并设置对 PCI、PCI/X 或 PCI Express 配置空间进行后续访问所用的资源
内核统计信息 (kstat) 函数包括:
创建并初始化新的 kstat
向系统中添加完全初始化的 kstat
初始化已命名的 kstat
记录从运行队列到等待队列的事务迁移
记录向运行队列中添加的事务
记录从运行队列Φ移除的事务
记录向等待队列中添加的事务
记录从等待队列中移除的事务
记录从等待队列到运行队列的事务迁移
内核日志记录和列显函数包括:
将消息提交至日志驱动程序
显示 SCSI 请求检测消息
显示与 SCSI 设备有关的消息
显示 SCSI 请求检测消息
缓存 I/O 函数包括:
禁止取消异步 I/O 请求
暂停以待處理方式完成块 I/O 的进程
在完成缓冲区 I/O 传送后释放缓冲区并通知阻塞的线程
使用单向电梯查找策略对缓冲区排序
在 I/O 完成后重用专用的缓冲区頭
将设备字节转换为页(向下舍入)
将设备字节转换为页(向上舍入)
将以字节表示的大小转换为以页表示的大小(向下舍入)
将以字节表示的大小转换为以页表示的大小(向上舍入)
将以页表示的大小转换为以字节表示的大小
表 B–11 过时的虚拟内存函数
设备 ID 函数包括:
返回設备 ID 的大小
从以前编码的字符串中解码设备 ID 和 minor_name,分配并返回指向提取部分的指针
释放在初始探测期间分配的资源
重置 SCSI 总线或目标
向目标驱動程序通知总线重置
解码 SCSI 外围设备类型
解码 SCSI 包完成原因
显示 SCSI 请求检测消息
显示与 SCSI 设备有关的消息
显示 SCSI 请求检测消息
返回索引匹配功能字符串
资源映射管理函数包括:
分配资源映射必要时等待
从资源映射中分配空间,必要时等待
将空间重新释放到资源映射中
确定系统是否处於紧急状态
不可轮询设备的错误返回函数
在内核的地址位置之间复制数据
查找长整数中设置的第一位
查找长整数中设置的最后一位
以 16 位半芓交换字节
比较两个以 null 结尾的字符串
比较两个以 null 结尾的字符串长度有限制
确定字符串中的非空字节数
将字符串从一个位置复制到另一个位置
将字符串从一个位置复制到另一个位置,长度有限制
将整数转换为十进制字符串
将十进制字符串转换为整数
返回两个整数中的较大值
返回两个整数中的较小值
查找变量参数列表中的下一个值
复制变量参数列表的状态
删除指向变量参数列表的指针
查找指向变量参数列表开頭的指针
本附录为要将设备驱动程序转换为支持 64 位内核的设备驱动程序编写人员提供信息本附录还介绍了 32 位设备驱动程序和 64 位设备驱动程序之间的区别,并说明了将 32 位设备驱动程序转换为 64 位设备驱动程序的步骤这些信息仅适用于常规字符设备驱动程序和块设备驱动程序。
本附录提供有关以下主题的信息:
对于仅需支持 32 位内核的驱动程序现有 32 位设备驱动程序将仍然有效,无需重新编译但是,大多数设備驱动程序需要进行一些更改才能在 64 位内核中正确运行且所有设备驱动程序都需要重新编译以创建 64 位驱动程序控制模块总线关闭怎么解決。本附录中的信息旨在指导您利用通用源代码来生成 32 位和 64 位环境的驱动程序从而提高代码可移植性并降低维护工作量。
开始修改设备驅动程序以便使用 64 位环境之前应了解 32 位环境与 64 位环境之间的区别。特别是必须熟悉 C 语言数据类型模型 ILP32 和 LP64请参见下表。
因 ILP32 与 LP64 之间的差异洏导致的特定于驱动程序的问题是本附录的主题更多常规主题将在中进行介绍。
除了清理常规代码以支持 LP64 的数据模型更改驱动程序编寫人员还必须提供对 32 位和 64 位应用程序的支持。
ioctl(9E)、devmap(9E) 和 mmap(9E) 入口点使应用程序和设备驱动程序之间可直接共享数据结构如果这些数据结构在 32 位环境与 64 位环境中的大小不同,则必须修改入口点以便驱动程序可确定应用程序的数据模型与内核的数据模型是否相同。如果数据模型不同则可对数据结构进行调整。请参见、和
在许多驱动程序中,只有少量 ioctl 需要这种处理其他 ioctl 无需更改即可应用,只要这些 ioctl 传递的数据结構大小不变
以下各节提供了有关转换驱动程序以在 64 位环境中运行的信息。驱动程序编写人员可能需要执行以下一项或多项任务:
使用硬件寄存器的固定宽度类型
使用固定宽度的公共访问函数。
检查并扩展派生类型的用法
检查 DDI 数据结构中更改的字段。
检查 DDI 函数中更改的參数
根据需要修改用于处理用户数据的驱动程序入口点。
下面详细说明这些步骤
完成每一步骤后,请修复所有编译器警告然后使用 lint 查找其他问题。对于 SC5.0(或更高)版本的 lint要想找出 64 位问题,必须在使用该命令时指定 -Xarch=v9 和
请勿忽略 LP64 转换期间出现的编译警告以前在 ILP32 环境中鈳安全忽略的警告现在可能表示比较严重的问题。
完成所有步骤后同时将驱动程序作为 32 位和 64 位控制模块总线关闭怎么解决进行编译和测試。
许多处理硬件设备的设备驱动程序使用 C 数据结构说明硬件的布局在 LP64 数据模型中,使用 long
或 unsigned long 类型定义硬件寄存器的数据结构几乎肯定不正确因为 long
类型现在是 64 位。首先包括 <sys/inttypes.h>然后将此类数据结构更新为使用
int32_t
或 uint32_t
,而不是 32 位设备数据的 long
此方法鈳保留 32 位数据结构的二进制布局。例如将以下代码:
Solaris DDI 允许通过访问函数访问设备寄存器,以便可在多个平囼间移植DDI 公共访问函数以前以字节和字等单位指定数据大小。例如ddi_getl( 9F) 用于访问 32 位。此函数不存在于 64 位 DDI 环境中且已被替换为可指定要处悝的位数的函数版本。
这些例程已添加到 Solaris 2.6 操作环境的 32 位内核中以允许驱动程序编写人员采用其早期版本。例如要在 32 位和 64 位内核间进行迻植,驱动程序必须使用 ddi_get32(9F) 而不是 ddi_getl(9F) 来访问 32 位数据
应尽可能使用系统派生的类型(如 size_t
),以使产生的变量在各种函数间传递时都有效而新的派生类型 uintptr_t
或 intptr_t
是整数类型,应该用于指针
固定宽度的整数类型用于表示二进制数据结构或硬件寄存器的显式夶小,而基础 C 语言数据类型(如 int
)仍然可用于循环计数器或文件描述符
设计使用这些派生类型的驱动程序时,请特别注意这些类型的用法尤其是驱动程序将这些值指定给其他类型(如固定宽度类型)的变量时。
DDI 数据结构中某些字段的数据类型(如 buf(9S))已被更改使用这些数据结构的驱动程序应确保正确使用这些字段。下面列出了变动很大的数据结构及字段
以下列出的字段与传輸大小(现在可超过 4 GB)有关。
结构定义 DMA 引擎和设备的属性因为这些属性指定寄存器大小,所以使用了固定宽度的数据类型而不是基本类型
结构包含 32 位 DMA 地址,因此使用了固定宽度的数据类型来定义该地址其大小已重新定义为
此结构中的这些字段无需增大,已重新定义为 32 位
pkt_statistics
字段无需增大,因此这些字段已重新定义为 32 位整数数据传输大小 pkt_resid 字段需要增大,已重新定义为 ssize_t
本节介绍已哽改的 DDI 函数参数数据类型。
在以前的发行版中value_p 被定义为 unsigned long
类型。在 64 位内核中drv_getparm(9F) 可提取 32 位和 64 位。此接口未定义这些量的数据类型可能会发苼简单的编程错误。
以下新例程提供更安全的替代方法:
强烈要求驱动程序编写人员使用这些例程而不要使用
nbytes 参数被定义为 long
类型,但是甴于 nbytes 以字节为单位表示大小因此 size_t
更适合。
在以前的发行版中 和 例程的 timeout 参数被定义为 long
类型。由于这些例程表示时间周期因此 clock_t
更适合。
茬以前的发行版中dev_advcnt 被定义为
如果设备驱动程序使用 、 或 与 32 位应用程序共享包含 long
或指针类型的数据结构,而驱动程序已针对 64 位内核进行了重新编译则数据结构的二进制布局将不兼容。 如果当前已按 long
类型定义了字段并且未使用 64 位数据项,请更改数據结构以使用仍为 32 位的数据类型(int
和
unsigned
int
)。否则驱动程序需要识别 ILP32 和 LP64 的不同结构形式,并确定应用程序与内核之间是否出现模型不匹配
要处理潜在的数据模型差异,需要编写可直接与用户应用程序交互的 ioctl()、devmap() 和 mmap() 驱动程序入口点以确定参数是否来自使用与内核具有相同数據模型的应用程序。
要确定应用程序与驱动程序之间是否存在模型不匹配驱动程序可使用 FMODELS 掩码确定 ioctl () mode 参数的模型类型。在 mode 中采用以下值之┅来标识应用程序的数据模型:
中的代码示例说明如 何使用
要使 64 位驱动程序和 32 位应用程序共享内存64 位驱动程序生成的二进制布局必须与 32 位应用程序使用的布局相同。要导出到应用程序的映射内存可能需要包含与数据模型有关的数据结构
很少内存映射设备会面临此问题,洇为在内核数据模型发生变化时设备寄存器不会改变大小但是,一些将映射导出到用户地址空间的伪设备可能要将不同数据结构导出到 ILP32 戓 LP64 应用程序要确定是否出现了数据模型不匹配, 可使用 model 参数说明应用程序期望的数据模型model 参数被设置为以下值之一:
由于 mmap(9E) 没有可用于傳递数据模型信息的参数,因此可编写驱动程序的 mmap(9E) 入口点以使用新的 DDI 函数 ddi_model_convert_from(9F)。此函数返回以下值之一以指示应用程序的数据类型模型:
戓者,迁移设备驱动程序以支持 devmap(9E) 入口点
您应认真检查 x86 平台上使用 64 位 long 类型(如 uint64_t)的结构。32 位模式编译与 64 位模式编译的对齐方式和大小可能鈈同请参考以下示例。
在 32 位系统中该示例显示以下结果:
而在 64 位系统中,该示例显示以下结果:
因此32 位应用程序与 64 位应用程序对结構的理解不同。这样尝试在 32 位和 64 位两种环境中使用同一结构可能会导致问题。这种情况经常发生尤其是在通过 ioctl() 调用将结构传入或传出內核的情况下。
许多 操作对一类设备驱动程序通用例如,大多数磁盘驱动程序实现 系列的众多 ioctls这些接口中有许多将数据结构复制到内核中,或从内核中复制出数据结构在 LP64 数据模型中这些数据结构的一部分已更改了大小。以下部分列出了对于 dkio、、、 和 系列的 ioctls现在需要茬 64 位驱动程序 ioctl 例程中显式进行转换的
nblocks 属性按块设备驱动程序的每一片导出。此属性包含 512 字节块的数量设备的每一片都支持这些块。nblocks 属性被定义为带符号的 32 位量这就将片的最大大小限制为 1 TB。
每个磁盘提供 1 TB 以上存储空间的磁盘设备必须定义 Nblocks 属性该属性仍应包含设备可支持嘚 512 字节块的数量。但是Nblocks 是带符号的 64 位量,它除去了对磁盘空间的任何实际限制
nblocks 属性现在已过时。所有磁盘设备都应提供 Nblocks 属性
用于系統控制台的帧缓存器驱动程序必须提供相应的接口,以使系统能够在控制台上显示文本Solaris OS 可提供增强的可视化 I/O 接口,以使内核终端仿真器能够直接在控制台帧缓存器上显示文本本附录介绍如何向帧缓存器驱动程序添加必要的接口,以使该驱动程序能够与 Solaris 内核终端仿真器进荇交互
内核终端仿真器的作用是按照帧缓存器的屏幕高度、宽度和像素深度模式确定的正确位置和表示法在控制台帧缓存器中呈现文本。终端仿真器还可以驱动滚动、控制软件光标以及解释 ANSI 终端转义序列。终端仿真器以 VGA 文本模式或像素模式访问控制台帧缓存器具体取決于图形卡。要将您的帧缓存器驱动程序用作 Solaris 控制台帧缓存器驱动程序它必须与 Solaris 内核终端仿真器兼容。目标平台是最重要的因素它决萣了您是否需要修改帧缓存器驱动程序,以使您的驱动程序与 Solaris 内核终端仿真器兼容
x86 平台-不需要修改控制台帧缓存器驱动程序,因为 x86 控淛台帧缓存器驱动程序已经支持控制台帧缓存器接口
SPARC 平台-控制台帧缓存器驱动程序应使用本附录中所述的接口,以使驱动程序能够与 Solaris 內核终端仿真器进行交互
vgatext 控制模块总线关闭怎么解决已经支持控制台帧缓存器接口,因此 x86 帧缓存器驱动程序与内核 tem 控制模块总线关闭怎么解决兼容不需要向 x86 帧缓存器驱动程序添加任何特殊的接口。
本附录的其余部分仅适用于 SPARC 平台
SPARC 帧缓存器驱动程序通常不在 VGA 文本模式下运行。SPARC 帧缓存器驱动程序通常需要发送像素图案以描述显示的文本和图像。内核 tem 要求 SPARC 驱动程序支持特定嘚接口以便在屏幕上呈现数据、执行滚动和显示文本光标。驱动程序实际上如何在屏幕上呈现 tem 发出的数据取决于具体的设备驱动程序通常根据硬件和视频模式在视频内存中绘制数据。
Solaris OS 提供的一些接口使内核终端仿真器能够直接驱动兼容的控制台帧缓存器将驱动程序转換为与内核终端仿真器兼容的好处在于:
极大地改善性能,尤其是滚动性能
增强 ANSI 文本颜色功能
能够在控制台帧缓存器上启动登录会话即使当系统控制台流定向到串行端口以外时也是如此
SPARC 控制台帧缓存器驱动程序不需要与内核终端仿真器兼容。如果控制台帧缓存器驱动程序鈈与内核终端仿真器兼容系统将使用 OpenBoot PROM 中的 FCode 终端仿真器。
控制台帧缓存器通过 EEPROM screen 环境变量进行识别系统通过检查帧缓存器驱动程序是否导絀 返回了兼容版本号,那么系统会将系统控制台配置为通过内核终端仿真器利用该帧缓存器驱动程序。有关 I/O 控制驱动程序入口点的信息请参见 手册页。
支持内核终端仿真器的 SPARC 驱动程序应导出 tem-support DDI 属性该属性表示驱动程序支持内核终端仿真器。如果帧缓存器驱动程序导出了 tem-support DDI 屬性则早在引导过程中配置控制台时就将会处理该驱动程序。如果帧缓存器驱动程序未导出 tem-support 属性则在引导过程中,可能不会那么早就處理该驱动程序
设置为 1 时,此 DDI 属性表示此驱动程序与控制台内核帧缓存器接口兼容
内核终端仿真器控制模块总线关闭怎么解决通过两種主要接口与控制台帧缓存器驱动程序进行交互:
通过 ioctl 接口(正常的系统操作期间)
通过轮询式 I/O 接口(独立模式期间)
内核终端仿真器通過两种接口与控制台帧缓存器驱动程序进行交互。在正常的系统活动期间(系统成功引导后)内核终端仿真器与控制台帧缓存器驱动程序之间的通信通过 ioctl 接口进行。在独立模式期间(系统引导之前或调试期间)内核终端仿真器与控制台帧缓存器驱动程序之间的通信通过輪询式 I/O 接口进行。内核终端仿真器与控制台帧缓存器驱动程序之间的所有活动都由内核终端仿真器启动但控制台帧缓存器驱动程序用来通知内核终端仿真器有关视频模式方面的变化的回调函数除外。
手册页中详细说明了控制台可视化 I/O 接口有关视频模式更改回调函数的更哆信息,请参见
在正常的系统活动期间,内核终端仿真器通过下表中列出的 ioctl 接口与控制台帧缓存器驱动程序进行通信:
对应的数据结构 |
---|
初始化终端仿真器控制模块总线关闭怎么解决与帧缓存器之间的会话请参见。 |
终止终端仿真器控制模块总线关闭怎么解决与帧缓存器之間的会话请参见。 |
以矩形显示像素请参见。 |
复制像素的矩形区(滚动)请参见。 |
显示或隐藏文本光标请参见。 |
将终端仿真器控制模块总线关闭怎么解决色彩表发送到帧缓存器驱动程序请参见。 |
从帧缓存器读取终端仿真器控制模块总线关闭怎么解决色彩表请参见。 |
接口的功能相同仅当操作系统处于静止状态并处于独立模式时,才调用轮询式 I/O 接口有关更多信息,请参见
处于独立模式时,内核終端仿真器通过下表中列出的轮询式 I/O 接口与控制台帧缓存器驱动程序进行通信: