Electronic Joint Business

Solution for E-Business

平台开发

IRP 操作详解

每个操作系统都需要一个显性或隐性的 I/O 模型来处理进出外设的数据流。而 Windows I/O 模型的特性之一就是支持异步 I/O,其它一些特点包括:1

  • I/O 管理器为所有内核驱动提供了一致的接口,无论是底层驱动,中间层驱动或者文件系统驱动。所有请求都以 IRP (I/O 请求包)的形式发送给驱动。
  • I/O 操作是层叠的。I/O 管理器提供 I/O 系统服务供用户模式下子系统调用来执行 I/O 操作。I/O 管理器负责解释这些调用,并创建一个或多个 IRP,然后将它们路由给堆叠的驱动层层传递到物理设备。
  • I/O 管理器定义了一整套标准例程,其中一些要求驱动必须支持,另一些则是可选的。所有驱动遵循相对一致的实现模型,并根据不同的外设而有所差异,另外总线驱动、功能驱动、过滤驱动和文件系统驱动等也有不同的功能要求。
  • 正如 Windows 操作系统一样,驱动也是基于对象的。驱动、设备和物理硬件都被表示为对象。I/O 管理器和其他系统组件提供了内核态的支持例程,驱动通过例程调用来操作相关对象使得工作得以完成。

除了用来传递传统的 IO 请求外,I/O 管理器也可以和PnP 管理器、电源管理器一起发送包含 PnP 和电源请求的 IRP。

用户的 I/O 请求和文件对象
由于内核驱动被环境子系统所隐藏,因此用户是不可见的,这些子系统实现了一些大家熟悉的编程接口,比如 Windows 或 POSIX。对用户态代码(包括子系统)来说,可见的只是 I/O 管理器所控制的命名文件对象(named file object) 。

图1-1 显示了用户、子系统和 I/O 管理器的关系。

诸如 Win32 子系统这样的受保护子系统,将 I/O 请求通过 I/O 系统服务传递给相应的内核驱动。上图所示的子系统依赖于显示、显卡适配器、键盘和鼠标设备驱动的支持。

>>> 阅读全文

 

, ,

Windows LPC 通信机制剖析

LPC (Local procedure calls) 是 NT 内核实现一种基于消息的高速通信机制,可用于用户进程之间、用户进程与内核驱动之间或者内核驱动之间的通信。举个用户态进程间通信的例子,比如在创建登录会话时,CSRSS.exe 就通过 SmssWinStationApiPort 和 SMSS.exe 沟通,或者进程可以通过 LsaAuthenticationPort 就安全问题与 LSASS.exe 沟通。又比如在读写加密文件时, KSecDD.sys 会因为 EFS 秘钥的加密和解密与 LSASS.exe 通信, 这是用户进程与内核驱动通信的例子。1

LPC 采用两种不同机制以便在服务端与客户端之间传递数据:如数据长度小于 304 字节,则使用 LPC 消息缓冲;反之,数据长度超过 304 字节,则使用共享内存 (通过 NtCreateSection ),该内存段会同时映射到服务端和客户端的地址空间中。

除了当作远程过程调用(Remote Procedure Calls)的备选协议外,LPC 还被广泛运用到整个系统中,比如 Win32 应用与 CSRSS.EXE 间的通信,SRM 和 LSASS间的通信以及 WinLogon 与 LSASS 的通信等等。

LPC 强制在客户端与服务端间采用同步通信模型。从 Vista开始, LPC 开始被废弃转而采用称为异步本地进程间通信(ALPC)的新机制。 和 LPC 相比,ALPC 固有的优势是:从客户端到服务端的所有调用都是异步的,即客户端不需要阻塞或等待服务器对消息作出响应。从 Vista 之后,如果某些老应用调用了 LPC API,则会被自动重定向到新的 ALPC API。

LPC API
LPC API 是原生 API,换句话说 API 分别通过 NTDLL.dll 和 NTOSKRNL.exe 导出到用户模式和内核模式。LPC API 并未被导出到 Win32 层,因此 Win32 应用不能直接使用 LPC。不过如果进行 RPC 通信时使用 “ncalrpc” 协议序列(协议序列代表 RPC 通信使用的网络协议。2,就可以指定 LPC 作为下层传输协议,从而让 Win32 应用间接使用 LPC。

>>> 阅读全文

 

, , ,

受保护进程的演进 <1>: Windows 8.1 如何抵御哈希传递攻击

6年多前我第一次发文讨论受保护进程的概念—《为什么受保护进程糟糕透顶》1,该标题已经清楚透露了我对这个未经深思熟虑的 DRM 方案的看法。显然之后微软对其内部机制进行了长考(的确,抛开 DRM,一个难以渗透的用户态进程在安全领域也是个有趣的课题),又创造了一类新进程:Protected Process Light,内核中通常缩写为 PPL。

和其笨重的兄弟(受保护进程)不同,Protected Process Light 作为安全屏障,为 Windows 平台带来了三种可以有效抵御威胁的安全增强。在接下来的系列文章里2,我们将会看到这些安全增强是如何实现的,本文先从如何抵御哈希传递攻击(Pass-the-Hash)3开始。

我们将涉及 LSASS 4 在 Windows 安全模型中的作用,然后讨论新的 PPL 模型背后的技术细节。要涵盖新的安全改进,我们也不得不涉及一些内部相关领域,所以我们也会对安全启动和保护变量稍加讨论。不过最重要的是,我们还将了解如何启用设置来抵御 PtH ,因为对于非 RT 的 Windows,该功能默认是禁用的。

LSASS 进程
Windows 使用众所周知的算法(NTLM)对本地用户帐户进行哈希运算并将结果保存到称为 SAM (安全帐户管理器) 的数据库中,SAM 本身是注册表的一个配置单元文件。和其他操作系统一样,总是存在各种脱机或在线攻击,目的不外是为了获取、重置,甚至重用保存在 SAM 中的哈希值,例如常见的”密码重置”应急启动盘,或者是恶意的权级提升等等。此外,还有其它一些加密数据存储在 SECURITY 数据库(也称为 LSASS 策略数据库),这是另一个注册表配置单元文件。该数据包括密文(secrets,如 LSA 密文信息),保存的纯文本密码等等。

Windows 通过被称为本地安全权威子系统(LSASS Local Security Authority Sub-System)的进程管理着这些信息的运行时状态,并最终负责所有登录操作 (包括远程登录到 Active Directory)。因此,为了要获得对这些数据的访问,主要通过用两种机制:

>>> 阅读全文

 

,

Linux环境下的图形系统和AMD R600显卡编程(7)——AMD显卡的软件中断

CPU上处理的中断可以分成“硬件中断”和“软件中断”两类,比如网卡产生的中断称为硬件中断,而如果是软件使用诸如”int 0x10″(X86平台上)这样的指令产生中断称为软件中断,硬件中断是异步的,其发生的时机是不可知的,但是软件中断是同步的,CPU是“确切”知道其发生的时机的。

  同样的,在GPU看来,中断也可以分成“硬件中断”和“软件中断”两类,比如热插拔事件或者vblank事件都会产生“硬件中断”,这些事件在GPU看来是异步的,GPU不知道这些事情何时发生。GPU也可以使用类似CPU的int指令那样产生中断,考虑这样一种情形:驱动向硬件发送了绘图命令后必须等到硬件执行完了这些命令后才能进行后续的操作,否则硬件的上一次命令没有执行完就继续执行下一次命令会导致错误。前面介绍scratch寄存器的时候提及过可以在命令末尾添加一条写scratch寄存器的命令,发送命令之后驱动使用轮询的方式轮询scratch寄存器,当然这种场合使用轮询肯定是不合适的,实际上显卡可以采用软中断机制,在完成绘图命令后执行一个类似“int xx”的命令产生中断,这里GPU是“确切”知道中断发生的时机的—-即在绘图命令完成的时候。

  前面提到的fence就是这种“软件中断”的具体应用。

  在上一篇blog中看到,fence是按照下面的步骤使用的:

  radeon_fence_create->radeon_fence_emit->radeon_fence_wait

>>> 阅读全文

 

Linux环境下的图形系统和AMD R600显卡编程(5)——AMD显卡显命令处理机制

  通常通过读写设备寄存器对设备进行编程,在X86系统上,有专门的IO指令进行编程,在其他诸如MIPS、SPARC这类系统上,通过将设备的寄存器映射到内存地址空间直接使用读写内存的方式对设备进行编程。

  Radeon显卡提供两种方式对硬件进行编程,一种称为“推模式”(push mode)即直接写寄存器的方式,另一种称为拉模式,这篇blog讨论拉模式,这也是驱动中使用的模式。

  在拉模式下,驱动使用命令流(Command Stream)的形式进行对显卡编程:驱动程序将需要对显卡进行配置的一连串命令写入命令缓冲区,写完之后进入让出处理器,显卡按照命令写入的顺序执行这些命令,执行完成后触发中断通知驱动。CPU将这些命令放入一个称为命令环的环形缓冲区中,命令环是GTT内存中分出来的一片内存,驱动程序往命令环中填充命令,填充完后通知GPU命令已经写入命令,GPU的命令处理器CP(Command Processor)。上一篇博客即是通过ring环内存的使用来说明如何在系统中分配内存以及建立映射关系的。

  驱动写入的命令流由命令处理器CP进行解析,具体来说,CP完成以下工作:
•接收驱动程序的命令流。驱动程序将命令流先写入系统内存,然后由CP通过总线主设备访问方式进行获取,当前支持三种命令流,除了前面说的环形缓冲命令流,还有间接缓冲1命令流和间接缓冲2命令流;
•解析命令流,将解析后的数据传输给图形控制器的其他模块,包括3D图形处理器、2D图形处理器、视频处理器。

命令环缓冲区

>>> 阅读全文

 

Linux 图形系统和 AMD R600 显卡编程(4)——AMD显卡显存管理机制

显存可以分为两部分,一部分是显卡自带的内存称为 VRAM 内存,另外一部分则是系统主存称为 GTT 内存(Graphics Translation Table,GTT 和后面的 GART 含义相同,都是指显卡的页表,GTT 内存可以就理解为需要建立 GPU 页表的显存)。在嵌入式系统或者集成显卡上,显卡通常是不自带显存的,而是完全使用系统内存。通常显卡上的显存访存速度数倍于系统内存,因而许多数据如果是放在显卡自带显存上,其速度将明显高于使用系统内存的情况(比如纹理,OpenGL 中分普通纹理和常驻纹理)。

某些内容是必须放在 VRAM 中的,比如最终用于显示的“帧缓存”,以及后面说的页表 GART (Graphics Addres Remapping Table),另外有一些比如后面将介绍的命令环缓冲区(Ring Buffer)是要放在 GTT 内存中的。另一方面,VRAM 内存是有限的,如果 VRAM 内存使用完了,则必须将一些数据放入 GTT 内存中。

通常 GTT 内存是按需分配的,而且是给设备使用的,比如 radeon r600 显卡最多可以使用 512M 系统内存( Linux 内核中是这样设置的),一次性分配 512M 连续的给设备用的内存在 linux 系统中是不可能成功的,而且即使可以成功,有相当多的内存是会被浪费掉的。按照按需分配的原则,使用多少就从系统内存中分配多少,这样得到的 GTT 内存在内存中肯定是不连续的。GPU 同时需要使用 VRAM 内存和 GTT 内存,最简单的方法就是将这两片内存统一编址(这类似 RISC 机器上 IO 和 MEM 统一编址),VRAM 是显卡自带的内存,其地址一定是连续的,但是不连续的 GTT 内存如果要统一编址,就必须通过页表建立映射关系了,这个页表被称为 GTT 或者 GART,这也是这些内存被称为 GTT 内存的原因。

和 CPU 端地址类似,我们将 GPU 使用的地址称为“GPU虚拟地址”,经过查页表之后的地址称为“GPU物理地址”,这些地址是 GPU 最终用于访存的地址,由于 GPU 挂接在设备总线上,因此这里的“GPU物理地址”就是“总线地址”,当然落在 VRAM 区域的内存是不用建页表的,这一片内存区域的地址我们只关心其 “GPU 虚拟地址”。

R600 显卡核心存管理有关的寄存器如表4-1示,目前并没有找到完整的描述这些寄存器的手册,表中的数据根据阅读代码获取到。

>>> 阅读全文

 

Linux 图形系统和AMD R600显卡编程(3)——AMD显卡简介

早期的显卡仅用于显示,后来显卡中加入了 2D 加速部件,这些部件用于做拷屏,画点,画线等操作。随着游戏、三维模拟以及科学计算可视化等需要,对 3D 的需求逐渐增加,早期图形绘制工作由 CPU 来完成,要达到真实感和实时效果,只能绘制一些简单的线框模型,上世纪80年代,斯坦福大学的 Jim Clark 教授率先提出用专用集成电路技术实现一个专用的 3D 图形处理器的设想,于 1984 年推出了世界上第一个通用图形工作站 IRIS1400。

AMD 最早的显卡从 R100 开始,一直到 R900(R600 以后也使用HD xxxx作为代号),R900(HD 6xxx)之后是HD 7xxx系列,目前最新的显卡使用 Rx 2xx代号,最新的是 Radeon R9 2xx 系列。这里只描述 R600 显卡的编程,因此只讨论 R600 之前和之后不久的显卡。

AMD 显卡的演变过程如下(参考wiki页和 Plan9 操作系统开发人员的PPT):

R100 是一款固定渲染管线的显卡,R200 采用了可编程处理器,R300 在 R200 的基础上发生了比较大的变化,此后的 R400 和 R300 差别不大。到 R500 的时候 GPU 除了有 vbios 外,还引入了 atombios,atombios 是一段比较简单的脚本,和具体平台无关,解释器解释执行(代码集成在内核驱动里面),然而 3D 核较 R300 变化不大,寄存器变化也比较少(主要变化在像素着色器部分)。

R600 在 R500 的基础上发生很大的变化,2D 部件被废除,3D 部件改成了统一着色器架构,GPU 的寄存器和原来完全不同,由于体系结构的变化,对硬件编程也和原来有了很大变化。R700 GPU 是 R600 的优化版,在驱动层面上,R700 的编程和 R600 的编程基本上是一样的,后续的 Evergreen、Southern Island 和 Northern Island 都是这种统一着色器架构的延续,因此理解 R600 的编程后将比较容易理解后续GPU核的编程。

>>> 阅读全文

 

Linux 图形系统和AMD R600显卡编程(2)——Framebuffer、DRM、EXA和Mesa简介

原文

Framebuffer 在 Linux 中是作为设备来实现的,它是对图形硬件的一种抽象,代表着显卡中的帧缓冲区(Framebuffer)。通过Framebuffer 设备,上层软件可以通过一个良好定义的软件接口访问图形硬件,而不需要关心底层图形硬件是如何工作的,比如,上层软件不用关心应该如何读写显卡寄存器,也不需要知道显卡中的帧缓冲区从什么地址开始,所有这些工作都由 Framebuffer去 处理,上层软件只需要集中精力在自己要做的事情上就是了。

Framebuffer 的优点在于它是一种低级的通用设备,而且能够跨平台工作,比如 Framebuffer 既可以工作在 x86 平台上,也能工作在 PPC 平台上,甚至也能工作在 m68k 和 SPARC 等平台上,在很多嵌入式设备上 Framebuffer 也能正常工作。诸如 Minigui 之类的 GUI 软件包也倾向于采用 Framebuffer 作为硬件抽象层(HAL)。

从用户的角度来看,Framebuffer 设备与其它设备并没有什么不同。Framebuffer 设备位于/dev下,通常设备名为fb*,这里*的取值从0到31。最常用到的 Framebuffer 设备是 /dev/fb0。通常,使用 Framebuffer 的程序通过环境变量 FRAMEBUFFER 来取得要使用的Framebuffer 设备,环境变量 FRAMEBUFFER 通常被设置为”/dev/fb0”。

从程序员的角度来看,Framebuffer 设备其实就是一个文件而已,可以像对待普通文件那样读写 Framebuffer 设备文件,可以通过 mmap() 将其映射到内存中,也可以通过 ioctl() 读取或者设置其参数,等等。最常见的用法是将 Framebuffer 设备通过 mmap() 映射到内存中,这样可以大大提高IO效率。

>>> 阅读全文

 

,

Linux 图形系统和 AMD R600 显卡编程(1) —— Linux环境下的图形系统简介

Linux/Unix 环境下最早的图形系统是 Xorg 图形系统,Xorg 图形系统通过扩展的方式以适应显卡和桌面图形发展的需要,然而随着软硬件的发展,特别是嵌入式系统的发展,Xorg 显得庞大而落后。开源社区开发开发了一些新的图形系统,比如 Wayland 图形系统。

由于图形系统、3D 图形本身的复杂性以及历史原因,Linux 图形系统相关的源码庞大而且复杂,而且缺少学习的资料(所有源代码分析或者驱动编程的书籍都很少介绍显卡驱动)。在后续一系列文章中,笔者将从对 AMD 硬件编程的角度出发对部分问题做一个简单的介绍,当然,这种介绍是很初级的,旨在希望能够对初学着有所帮助。

内核 DRM、Xorg 以及 Mesa 三部分加起来的代码和整个 Linux 内核的体量是差不多大的。而且现代的显卡上的 GPU 的复杂程度在一定程度上可以和 CPU 相聘美,从程序员的角度看,操作系统(CPU 的驱动)包含的许多功能在 GPU 驱动上都能够找到。比如说,GPU 有自己的指令系统,着色器程序(GLSL、HLSL、Cg 这类着色语言)需要编译成 GPU 的指令集,然后才能够在 GPU 上运行,符合着色语言规范的 3D 驱动都包含这样的一个编译器。3D 应用程序需要使用大量内存,GPU 在进行运算时需要访问这些内存,所以 GPU 访问内存时也使用一套和 CPU 页表一样的机制。另外,在中断系统上,GPU 和 CPU 也有相似之处。后面的一些内容将会陆续对这些问题做一个简单的介绍。

传统上 Linux 是一个宏内核,设备驱动大部分都是包含在内核里面的,内核代码最庞大的部分就是 drivers 目录,如果你从 kernel.org 上面下载一个内核源码,你会发现编译时间大部分都耗在编译设备驱动上。

对于微内核操作系统,设备驱动不是内核的部分。不过出于调试方便以及其他一些原因,Linux 操作系统上面的一些驱动是放在核外的。比如说打印机、扫描仪这类设备,当前的打印机扫描仪通常都是通过 USB 接口连接到计算机上的,对于这些设备的 Linux 驱动,除了 USB 核心部分在内核,这些打印机扫描仪本身的驱动都是在核外的。Linux 上面的打印机使用 CUPS 系统,CUPS 运行在核外,其驱动是按照 CUPS 的接口来开发的。Linux上面的扫描仪使用的则是运行在核外的 sane 系统,其驱动是以动态链接库的形式存在的。另外一类核外的驱动是图形系统的驱动,由于图形系统、显卡本身比较复杂,加上一些历史原因,图形系统的驱动在核内核外都有,且显卡驱动最主要的部分在核外。

>>> 阅读全文

 

, , , , , , , ,

Kubernetes 设计概览

Kubernetes 是用于管理跨主机的容器化(containerized)应用程序的系统,它为应用的部署、维护和扩展提供了基本机制。

Kubernetes 建立了强壮的声明式元语用于维护用户请求的预期状态。这些原语是 Kubernetes 的一大特色。此外还有自愈机制,如自动重启,重新调度,以及根据主动控制器而不单是业务流程的需要高对容器进行复制。

Kubernetes 主要适用于包含多个容器的应用,如弹性分布式微服务。它还设计用来将非容器化应用程序栈迁移到 Kubernetes。为此,它包括抽象为分组的松散耦合和紧密耦合的编队,容器,并提供容器查找,并以相对熟悉的方式互相交流的方式。

Kubernetes is primarily targeted at applications composed of multiple containers, such as elastic, distributed micro-services. It is also designed to facilitate migration of non-containerized application stacks to Kubernetes. It therefore includes abstractions for grouping containers in both loosely coupled and tightly coupled formations, and provides ways for containers to find and communicate with each other in relatively familiar ways.

Kubernetes enables users to ask a cluster to run a set of containers. The system automatically chooses hosts to run those containers on. While Kubernetes’s scheduler is currently very simple, we expect it to grow in sophistication over time. Scheduling is a policy-rich, topology-aware, workload-specific function that significantly impacts availability, performance, and capacity. The scheduler needs to take into account individual and collective resource requirements, quality of service requirements, hardware/software/policy constraints, affinity and anti-affinity specifications, data locality, inter-workload interference, deadlines, and so on. Workload-specific requirements will be exposed through the API as necessary.

>>> 阅读全文

 

, ,

利用总线接口进行驱动间通讯

这里我们将讨论高级 WDF 驱动开发中最常见的话题之一: 驱动间的通信。当引入 Windows 驱动开发其他话题,貌似简单的驱动间调用很快就变成一系列无穷无尽的选项、功能以及晦涩难懂的 WDM 琐事。1

不过从这些讨论中我们看到了希望之光:总线接口还存在着并活跃在 Windows 中,它不但提供了简洁的、定义良好的方式用于驱动间通信,而且 KDMF 还提供了帮助例程用来快速生产或消费这些接口。

什么是总线接口?
正如其名称所示,总线接口是总线驱动为其子驱动提供的一种标准程序调用接口。总线驱动可以有多个总线接口,每个接口通过 GUID 标识。接口的使用者通过 PnP IRP 来查询接口并返回一个总线定义的数据结构,该数据结构可以包含任何总线驱动想要共享的数据或函数 (如图1-1)。

当总线驱动向其子驱动的提供总线接口时,我们预期只有该 PDO 设备栈中的驱动将使用此接口。这样在卸载驱动时就可以消除任何可能存在的竞态。因为设备栈是从顶向下被逐一销毁的,因此 PDO 总是最后一个被删除的设备。假如总线接口被其设备栈内的驱动所使用,我们就无需担心在 PDO 被删除之后,还有程序试图使用该接口。

总线接口不只是给总线的
显然在总线驱动之外总线接口也相当有用,驱动间通信很常见且不是所有的驱动间通信都只涉及到与自己的 PDO 交互。还好,操作系统中对总线驱动的支持相当普遍,因此过滤型驱动或 FDO 可以对适当的 PnP IRP 进行处理,并发布自己的总线接口。这意味着我们可以使用由另一不同的设备栈 (图 2) 产生的总线接口。

>>> 阅读全文

 

, ,

编写虚拟 Storport 微端口驱动(一)

Storport 广受虚拟存储设备驱动编写者的欢迎。在 Storport 出现前,要完成类似的工作,你不得不修改(hack) SCSIport 微端口驱动,或者自己写个完整的 SCSI 端口驱动。修改微端口的方法十分复杂 (由于锁的问题)、 难以获得支持或者维护,而且性能较差。而编写完整的 SCSI 端口驱动的方法虽然性能不错,但技术难度高,而且也不支持 Windows 徽标认证。因此,这一领域的开发工作只限于那些愿意冒险、敢于尝试、而且不打算过徽标认证的公司和个人。1

Storport 是跟着 Windows Server 2003 被引入的,用来满足 RAID 和 SAN 环境的性能要求,这是以前的 SCSIport 驱动所不具备的。后续在 Windows Vista SP1 和 Server 2008 中,微软又更新了 Storport,提供了对 Storport 虚拟微端口驱动的支持。这个更新终于让存储驱动编写者拥有了一个能导出虚拟设备的模型。

对于虚拟微端口驱动的编写来说,Storport 模型相当不错。它提供了诸如 I/O 队列管理 (如队列深度、到达队列深度阀值时对 I/O 进行处理)、 I/O 错误处理 (如重置、重试等)、 启动或停止 PnP 设备 (LUN) 所需的所有操作以及总线驱动的所有职能。它只是无法提供硬件管理方面的帮助,因为我们开发的是虚拟微端口,所以并未存在任何硬件。另一方面,虚拟微端口驱动则要完全负责处理 I/O 请求。虽然听起来令人生畏,不过作为虚拟微端口驱动,你有全套的内核 API 和其它驱动程序来帮助完成这一工作。

开始
可能你从未接触过 Storport ,所以这里先了解一些基础知识。当你利用 Storport 模型进行开发时,这意味着你的驱动需要将接口暴露给 Storport 驱动 (Storport.sys),这是通过预定义的 API 和数据结构完成的,而不是基于 IRP。与 SCSI 端口/微端口模型类似,Storport 驱动被称为端口驱动,提供了微端口驱动进行操作的环境和支持例程,如此我们的适配器才对 Windows 存储子系统可见。这里适配器可以是物理设备或者虚拟设备,可以控制多条 SCSI 总线或多个 SCSI 设备。基于该模型所开发驱动即微端口驱动,图1-1 显示了 Storport 模型。

Storport 微端口驱动必须符合预定义的 Storport 规则以便将适配器(虚拟或物理)的服务提供给操作系统。Storport 通过 SCSI_REQUEST_BLOCKS (SRB — SCSI 请求块) 来调用微端口驱动, SRB 描述了要执行的操作。与 IRP 类似,SRB 包含了微端口驱动执行操作需要的所有信息。它包含一个操作码、 缓冲区以及用来描述请求的参数。驱动执行 SRB 描述的操作、将完成状态放入 SRB ,并完成请求时通知 Storport。该过程与普通驱动处理 IRP 不一样。

>>> 阅读全文

 

, , ,

ZigBee, XBee 和 MQTT

文章评价:
802.15.4 是由 IEEE 定义的无线网络通讯协议。它设计用于那些优先考虑低成本和低功耗而非速度和范围的应用程序。它可用来实现无线个人局域网 (WPAN),如此称呼是因为 WPAN 通常用于个人设备,如手机、 电脑和电子记事本之间的互联。1

WPAN 十分适用于物联网中传感器设备间的相连。Zigbee 规范是基于 802.15.4 开发出来的技术,其目的是提供在设备之间提供加密的无线通信,这时候成本低、 电池寿命长就显得格外重要。XBee 则是 Digi 公司的生产的 ZigBee 无线套件的俗称。

在 802.15.4 的定义中,每个 WPAN 有个唯一的协调器 (Coordinator),作为网络的主控制器主节点,管理其网络中的其他节点(路由和子节点)。在 XBee 中它被称为 ZigBee 协调器,通过配置,可在多种模式中运行。

本文我们将演示如何通过简单的技术使得来自 Zigbee WPAN 的传感器数据能与云端的 MQTT 代理(broker)进行 SSL 加密互联,如图 1-1 所示。在构建物联网方案原型时,该技术特别有用。因为它只依靠无线网络来访问数据流,因此多数情况不需要修改传感器端点。

在该方案中,我们将 XBee 协调器经 USB 适配器连接到处理器或者电脑的 USB 端口上,并在处理器上运行用 C 语言编写的守护进程。通常我们会选用刷了 OpenWRT 的迷你路由器充当处理器,因为它具有低功耗、占用资源少的特点,并可经无线或者有线(RJ-45)连接到互联网上,如图1-2 所示。

>>> 阅读全文

 

, , ,

基于 Azure 的物联网应用 — 宠物追踪器

本文介绍如何用 Azure 来实现一个 IoT 应用 — 宠物追踪器。这里是线上演示

根据统计每年大概有1千万只宠物走失。所以这篇文章将配合 IoT 和 Azure 等相关技术,帮你轻松地定位走失的宠物。1 ;当然本文所使用的硬件目前只适合用于产品原型或者实验目的,现实中应该根据宠物的大小来选择小而轻的元件和芯片来构建,因为没有人希望狗狗背个沉甸甸的东西。这里用到的硬件有:

  • Arduino
  • GSM/GPRS 扩展卡
  • GPS 扩展卡
  • 可充电电池套件

除了上述 IoT 设备,主要用到的技术还包括:

  • Azure Worker Role – TCP 监听器
  • Azure 网站,用来显示追踪宠物的地图

背景
如果你对 Arduino 不熟悉,请先阅读一下相关背景知识:Arduino 基础 GPRS 扩展卡基础

图1-1 是个简化框图,显示了这个应用是如何工作的。

>>> 阅读全文

 

, ,

小议微端口驱动、端口驱动和类驱动之间的关系

驱动程序由CLASS DRIVER,PORT DRIVER,MINIPORT,三部分组成,从层次上来说,LCASS DRIVER是针对几大类设备的驱动,比如存储设备驱动,就可以通过一个CLASS DRIVER来统一管理,完成一些这类设备共有的操作,主要是与设备无关的操作.PORT DRIVER从层次上来说,是在CLASS DRIVER和MINIPORT中间的一层驱动,相当与在CLASS DRIVER这个大类上面,在细分一些小类,把这些小类的共同操作写到这个驱动中,但是从功能上面说,PORT DRIVER又在MINIPORT之下,因为PORT DRIVER完成的操作可能是同步等等相当具体的功能,所以由PORT DRIVER提供具体操作供MINIPORT调用.MINIPORT则是针对每一个具体的设备的驱动,从层次上是在最底层,但是在功能上却是调用PORT DRIVER提供的功能来实现的.所以功能上来说,确实处于中间层次.

详解Windows 2000/XP Class/Port/Miniport驱动模型

对于软件复用,Microsoft Windows在用户层提供了COM(Component Object Model),其实现了二进制层级的兼容,使Windows开发进入了组件时代。COM的概念之一进程内组件,在用户态使用动态联接库作为载体。所以不管在COM之前或是之后,DLL都是Windows下实现软件复用的一个最主要的途径。只是单纯的DLL并未实现COM一样的二进制兼容的目的。但对于驱动开发者而言,不同于用户态的代码,2000/XP并未有相应的像COM一样的机制,实现核心态的二进制兼容方式。实际上对于内核态也没有必要提供一个像ole32.dll在用户态实现的COM Library这样的复杂机制(用户态COM组件遵循的简单的规则主要隐藏在COM Library的复杂之下)。

传统的DLL复用模式同样的适用于核心态代码的开发,加上为了简化同一类型设备开发工作等目的,Windows 2000/XP形成了Class/Port/Miniport这样的概念。我们知道对于Driver其提供的.sys文件实际与dll没有什么实质上的变化。我们首先讨论一下Class/Port/Miniport的概念与这种机制带来的益处:

1、我们知道PC机硬件通常可分成许多大类,如存储类设备等等。各大类又分成许多小类。如存储类设备又可分为Cdrom、Tape、Harddisk等等。对于每一类设备,提供一个class driver。这样的driver实现某一类型设备Driver与设备无关的公共的功能集合。对于Driver开发者而言,有了class driver的介入,仅仅需要实现一部分需要针对特定设备的功能,IO管理器需要的功能要不由class driver直接完成,要不就由class driver通过调用底层的模块来实现。class driver通常由Microsoft提供,通常实现的是设备无关的部分,这里的与设备无关主要是指不直接操作设备硬件。而这底层的模块通常称为miniport driver,后者由port driver提供服务(port driver类似于用户态DLL,不过她还实现一些简化设备驱动编写的功能,例如隐藏对IRP的繁琐操作等等)。Class driver调用miniport driver的方式主要有Device IOCTL,class driver导出的例程(就是DLL的概念)或是通过回调函数等等。这样分离出共有的部分,即可以实现所谓的复用,既减少了系统资源的占用,又减轻了开发工作量。例如对于存储类设备Microsoft分别提供了供了cdrom.sys,tape.sys与disk.sys三个class driver。这三个driver之中当然也存在一定的共同点,毕竟他们都属于存储类设备(底层硬件的区别通过miniport driver来区分)。Windows提供了classpnp.sys,三个driver将一些通用的例程置于这个sys中。这才更像是文章开头介绍的DLL复用技术,而不是这里介绍的class/port或是miniport driver。我在此段开头定义class实际上特别提出了与设备无关的共有功能的集合。即class driver实现的是与设备硬件无关的部分,这样做的好处是对于用户态的客户程序来说,不管对于scsi还是ide的设备,我们都可以使用一样的io操作来进行读写等操作,这里面的主要不同由class driver分发不同的请求至相应的port/miniport driver来实现对用户的透明。这才是最主要的class driver的目的。Microsoft还提供了一个miniclass的概念,在本文未加以叙述(具体请自行参考相关文档)。

>>> 阅读全文

 

,

Previous Posts Next posts