Enterprise Just Builder

Solution for Enterprise Software Architecture

Windows 调试集锦 <1>

调试 WinLogon1
WinLogon 是一个用户模式进程,负责处理用户登入登出的交互任务,以及处理 CTRL+ALT+DELTE。要调试 Winlogon 最简单的办法是使用 NTSD 然后通过内核调试器来控制并调试。

首先要解决的是如何将用户态调试器 NTSD 的输出重定向到内核调试器,为此需先配置内核调试连接。详细可以参考[2. Controlling the User-Mode Debugger from the Kernel Debugger[

其次需要修改注册表,这样 Winlogon 进程一开始启动就可被调试。注册表键值如下:

[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\WinLogon.EXE]
"Debugger"="ntsd -d -x -g"

The -d option passes control to the kernel debugger. The -x option causes the debugger to capture access violations as second-chance exceptions. The -g option causes the WinLogon process to run after the attachment. Do not add the -g if you want to start debugging before Winlogon.exe begins (for example, if you want to set an initial breakpoint).

In addition, you should set the GlobalFlag value under the winlogon.exe key to REG_DWORD “0x000400F0”. This sets heap checking and FLG_ENABLE_KDEBUG_SYMBOL_LOAD. However, since this second flag only affects the kernel debugger, symbols must also be copied to the target computer before starting the debugger.

>>> 阅读全文

Windows 驱动开发 <1> 理解 Windows 驱动的执行上下文

要理解 Windows 内核驱动,很重要的是要了解一个驱动函数是在哪一种”上下文”中执行的。如果你从事文件系统的开发、或 Windows 内核驱动的编写,透彻理解执行上下文将使你获益匪浅。了解上下文并小心使用,可以让你设计出高性能、低开销的内核驱动。

本文将探讨执行上下文的概念。在文章末尾,沃恩还会介绍一个驱动作为概念演示,该驱动可以允许用户态程序运行在内核模式中,因此拥有内核模式的所有权限与特权。此外,我们还将讨论设备驱动程序的执行上下文及其实际用途。1

什么是上下文
当提到某个例程的上下文时,其实指的是它的线程和进程执行环境。在 Windows NT 中,该环境是由当前的 TEB (Thread Environment Block) 和 PEB (Processes Environment Block) 所建立的。因此,上下文中将包括虚拟内存配置 ( virtual memory settings — 用于说明物理内存页与虚拟内存地址的对应关系) 、句柄对照表 (handle translations, 因为句柄是特定于进程的)、分发器信息( dispatcher information)、栈(stacks) 、通用和浮点寄存器集等内容。

如果我们问“某个内核例程所运行的上下文是什么”,实际上的问题是“内核分发器所建立的当前线程是什么”。由于每个线程仅可属于一个进程,所以当前线程同时也就意味着某个当前进程。当前线程和当前进程合在一起,就意味着我们前面提到的句柄、虚拟内存、调度状态等等,这些东西使得线程和进程具有唯一性。

对于内核驱动程序员来说, 上下文中最有用的也许就是虚拟内存上下文。如果你还记得 Windows 将用户进程空间映射到低 2GB 的虚拟内存地址中,而操作系统代码则被映射到高 2GB 虚拟内存空间中。当用户进程中的某个线程被执行时,其虚拟地址将位于 0~2GB 的范围中。所有高于 2GB 的地址都被设置为“不可访问”,以防用户直接访问操作系统的代码和数据结构。当操作系统代码被执行时,其虚拟地址范围是 2~4GB。

>>> 阅读全文

,

USB 协议详解之一 基础知识

在 USB 出现前,计算机上就已经存在众多接口标准,比如串口、并口、PS2 等等,各接口从硬件形状和软件设置都不兼容,因此 USB 的设计目标之一,就是希望通过它方便地实现设备之间的互联。从而解决接口标准太多的弊端,这也是 USB 中的 Universal 一词的含义。

USB 使用一个 4 针的标准插头,采用菊花瓣形式把所有外设连接起来,它使用串行方式传输数据,支持多数据流和多个设备并行操作并允许外设热插拔。

基础知识
从物理结构上,USB 系统是一个分层的星形结构,它包含三类硬件设备:主机(HOST)、 设备(DEVICE)和集线器(HUB)。处于每个星形拓扑中央的是集线器,而在主机与集线器之间,集线器与集线器之间,集线器与设备之间都是点对点连接。1

各个设备在系统中的作用如下:

  • USB 主机 的主要作用包括: 提供电源,同时进行节电管理;检测设备,包括设备的接入与断开;管理数据传输,包括控制流和数据流;发送配置请求对 USB 设备进行配置操作;对总线上的错误进行管理和恢复等等。
  • USB 设备:在一个 USB 系统中,设备和集线器的总数不能超过 127 个。USB 设备接收 USB 总线上所有数据包,通过数据包的地址域来判断是不是发给自己的数据包:若地址不符,则简单地丢弃该数据包;若地址相符,则通过响应主机的数据包来和 USB 主机进行数据传输。
  • USB 集线器:集线器用于设备扩展连接,所有 USB 设备都连接在 USB 集线器的端口上。一个 USB 主机总与一个根集线器 (USB ROOT HUB)相连。USB 集线器为其每个端口提供 100mA 电流供设备使用。同时,USB 集线器可以通过端口的电气变化来判断出设备的插拔操作,并通过响应 USB 主机的数据包把端口状态汇报给主机。一般来说,USB 设备与USB 集线器间的连线长度不能超过 5米,USB 系统的级联不能超过5层(包括ROOT HUB)。

USB 功能
USB 是一种串行接口协议,它依靠 D+/D- 两条数据线构成的差分线来进行数据传输,这和我们熟悉两线 RS232/485 协议有何区别呢?了解这种区别有助于深入理解 USB 。所以首先让我们回想一下 RS232 的数据是如何传送的,如图1-2:

>>> 阅读全文

, ,

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 系统服务传递给相应的内核驱动。上图所示的子系统依赖于显示、显卡适配器、键盘和鼠标设备驱动的支持。

>>> 阅读全文

, ,

用 IDA Windbg 调试器实现 VMWare 上的 Windows 内核调试

文章评价:
IDA 是交互式反汇编器(Interactive Disassembler)的简称,它由总部位于比利时列日市(Liège)的 Hex-Rays 公司的一款产品。IDA是一种递归下降反汇编器。其主要优势在于呈现尽可能接近源代码的代码。它不仅使用数据类型信息,而且通过派生的变量和函数名称来尽其所能地注释生成的反汇编代码。这些注释将原始十六进制代码的数量减到最少,并显著增加了向用户提供的符号化信息的数量。

和 Windows 原生的调试器 windbg 相比, IDA 可以将程序结构和算法的核心以类似 C 语言的形式呈现,因此更容易通过阅读代码来定位问题的所在。

本文将介绍如何透过 IDA 的 Windbg 插件来实现 Windows 内核调试。

使用 WinDbg 进行 Windows 内核调试通常需要两台计算机,一台称为Debuggee,即目标机,另一台作为 Debugger,也称为主机 HOST。

目标机可以是物理机或虚拟机。如果是物理机,那么该机器至少需要一个串口、1394口或者支持 USB 调试的 USB 端口,另外你还需要与对应的调试连接线,如串口线、1394总线、USB 2.0 或 3.0 调试线等等。 Windows 8 之后的操作系统,普遍使用 USB 3.0 端口进行调试,通过 USBView 工具查看目标机,可以确定机器上哪一个 USB 端口支持调试。

>>> 阅读全文

, , , ,

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)。因此,为了要获得对这些数据的访问,主要通过用两种机制:

>>> 阅读全文

,

基于 ASP.NET 开发多租户应用

在本文中,我们将创建一个多租户(multi-tenant)的 SaaS 应用,用到的技术包括:

  • 应用框架:ASP.NET Boilerplate
  • Web 框架:ASP.NET MVC 和 ASP.NET Web API
  • ORM : Entity Framework
  • SPA 框架:Angularjs
  • HTML/CSS 框架:Bootstrap

在阅读本文之前1,读者可以先试试在线演示

创建应用模板
ASP.NET Boilerplate 提供了许多模板可以更快地创建启动项目。利用 http://aspnetboilerplate.com/Templates 的模板,创建启动项目如下:

这里选择的是 “ABP + module zero” 模板 ( zero 模块为框架添加了用户、角色、租户…等等管理基础件),该模板为我们创建了一个“即用”的解决方案,包括登录页面、导航以及一个基于 bootstrap 的布局。下载之后,你就可以通过 Visual Studio 打开该解决方案,其层级结构(包括单元测试项目)如下:

First, we select EventCloud.Web as startup project. Solution comes with Entity Framework Code-First Migrations. So, (after restoring nuget packages) we open the Package Manager Console (PMC) and run Update-Database command to create the database:

, , , ,

Hazelcast 简介

Hazelcast 是一个开源的内存数据网格(IMDG)解决方案,它提供了可伸缩的分布式内存计算,对提高应用性能来说,Hazelcast 公认是最快且最具可扩展性的途径。特别是, 它提供大家十分熟悉的 Java 接口如 Map, Queue, ExecutorService, Lock, JCache 等的分布式实现,使得分布式计算变得更为简单。比如通过 Map 接口提供了内存键值存储,在保持了友好性的同时,还获得 NoSQL 的诸多优势的同时,提高了生产力。

除了分布式内存数据结构,Hazelcast 还提供一整套方便的 API 来访问集群中的 CPU 从而得到最快的处理速度。Hazelcast 设计目标之一是轻量化、便于使用。 因此 Hazelcast 的分发包只有一个紧凑的库 (JAR)文件,除了 Java 它不依赖其他东西,因此很容易将它插入解决方案中,从而得到分布式数据结构和分布式计算的能力。

Hazelcast is highly scalable and available. Distributed applications can use Hazelcast for distributed caching, synchronization, clustering, processing, pub/sub messaging, etc. Hazelcast is implemented in Java and has clients for Java, C/C++, .NET as well as REST. Hazelcast can also speak memcache protocol. It also plugs in to Hibernate and can easily be used with any existing database system.

If you are looking for In-Memory speed, elastic scalability and the developer friendliness of NoSQL, Hazelcast is a great choice for you.

, , ,

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显卡编程(6)——AMD显卡GPU命令格式

前面一篇blog里面描述了命令环缓冲区机制,在命令环机制下,驱动写入PM4(不知道为何会取这样一个名字)包格式的命令对显卡进行配置。这一篇blog将详细介绍命令包的格式。

  当前定义了4中命令包,分别是0型/1型/2型和3型命令包,命令包由两部分组成,第一部分是命令包头,第二部分是命令包主体,命令包头为请求GPU执行的具体操作,命令主体为执行该操作需要的数据。

•0型命令包

  0型命令包用于写连续N个寄存器。包主体部分是依次往这些寄存器写的值。包头各个部分的意义为:

 Linux内核代码./drivers/gpu/drm/radeon/r600.c r600\_fence\_ring\_emit函数有如下语句:

>>> 阅读全文

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效率。

>>> 阅读全文

,

Previous Posts Next posts