Enterprise Just Builder

Solution for Enterprise Software Architecture

linux

Linux和Windows设备驱动架构比较

本文将考查最为广泛使用的 Windows 和 Linux 操作系统的设备驱动架构。我们首先将展示并比较在这些操作系统中实现设备驱动所需的组件,然后讨论实现驱动程序的过程,包括对内核缓冲区执行 I/O 操作。在文章的末尾我们还将了解这些操作系统所提供的开发环境和基础工具。1

1.引言
现代操作系统一般都包含多个模块,如内存管理器、进程调度器、硬件抽象层和安全管理器等等。想进一步了解这两种操作系统的内核,这里有一些参考资料:关于 Windows 内核的细节,可翻阅 Russinovich 著的《Windows Internal》一书;而 Linux 内核则可以参考 Rusling 的《The Linux Kernel》或者 Beck et al 等合著的《Linux Kernel Internals》。对和各类型硬件设备交互来说,内核可被视为一个黑盒。那么能否将和所有已知设备交互的功能内建到内核中呢?有可能,但没有实际意义,因为这会无谓地消耗太多系统资源。

内核模块化
对于各种新设备,内核无法在创建时就预知如何与之交互。现代操作系统的内核允许通过运行时添加设备驱动模块来扩展系统功能,该模块实现的功能使得内核可以与某种特定的新设备交互。这些模块通常都会实现一个例程供内核在模块被加载时调用,此外还有例程则在模块被移除时调用。模块还会实现各种不同的例程以便实现 I/O 功能,如将数据传送到设备或从设备接收数据;同时还有例程以便向设备发送 I/O 控制指令。以上所述对 Linux 和 Windows 两种驱动架构均适用。

本文的组织结构
本论文分成下面几节:

  • 对两种驱动架构的一般介绍 (第二节)
  • 详细论述两种驱动架构的各个组件 (第三节)
  • 驱动程序范例,包括如何对内核缓冲区执行 I/O 操作(第四节)
  • 相关驱动开发环境和基础工具(第五节)

相关著作
Windows 设备驱动架构相关文档可在 Windows 驱动开发包(DDK)中找到. 此外 Walter Oney 和Chris Cant 在 《Writing Windows WDM Device Drivers》一书中对 Windows 驱动架构进行了详细介绍。Linux 设备驱动架构可以参考 Rubini 的《Linux Device Drivers》,该书可免费获取。

>>> 阅读全文

 

, , , , ,

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 系统,其驱动是以动态链接库的形式存在的。另外一类核外的驱动是图形系统的驱动,由于图形系统、显卡本身比较复杂,加上一些历史原因,图形系统的驱动在核内核外都有,且显卡驱动最主要的部分在核外。

>>> 阅读全文

 

, , , , , , , ,

Linux 设备驱动(一) PCI 设备枚举

本文将讨论 Linux 内核如何初始化系统的 PCI 总线和 PCI 设备。所谓 PCI — Peripheral Component Interconnect 即外部设备互联,PCI 标准是描述如何将系统中的设备以一种结构化、可控制的方式连接在一起的规范,包括系统外部设备的连接方式以及符合标准的设备组件应具备的行为规范。PCI 总线作为处理器系统的局部总线,主要目的是为了连接外部设备。较之前的存在其他总线如 ISA、EISA 和 MCA 总线相比,PCI 具有许多突出的优点:

  • PCI 总线空间与处理器空间隔离。PCI 设备具有独立的地址空间,该空间与存储器地址空间通过 HOST 主桥隔离。
  • 可扩展性。在 PCI 总线中,HOST 主桥可以通过 PCI 桥(PCI Bridge)扩展出一系列 PCI 总线,形成以 HOST 主桥为根节点的 PCI 总线树。该总线树上最多能挂接 256 个 PCI 设备(包括 PCI 桥)。
  • 动态配置机制。每个 PCI 设备都有独立的配置空间,包含设备在 PCI 总线中使用的基地址。基地址由系统软件动态配置并保证唯一性,从而解决了地址冲突的问题,实现了“即插即用” 的功能。PCI 桥的配置空间中则含有其 PCI 子树所能使用的地址范围。
  • 总线带宽。与之前的局部总线相比,PCI 总线极大提高了数据传送带宽,如 32位/33MHz 的 PCI 总线可以提供 132MB/s 的峰值带宽,而 64位/66MHz 的 PCI 总线可提供的峰值带宽为 532MB/s。
  • 共享总线的仲裁机制。PCI 设备通过仲裁获得 PCI 总线的使用权后才能进行数据传送;在 PCI 总线上进行数据传送,并不需要处理器进行干预。
  • 中断机制。PCI 总线上的设备可以通过四根中断请求信号线 INTA~D# 向处理器提交中断请求。PCI 总线上的设备可以共享这些中断请求信号。

一、PCI 总线组成结构
PCI 总线作为处理器系统的局部总线,是处理器系统的一个组成部件。讲述 PCI 总线的组成结构不能离开处理器系统这个大环境。在一个处理器系统中,与 PCI 总线相关的模块如图1‑1所示。

在一个处理器系统中,与 PCI 总线相关的模块包括:HOST 主桥、PCI 总线、PCI 桥接器和 PCI 设备。对于一些简单的系统,可能不含有 PCI 桥接器,这时所有设备都连接在 HOST 主桥引出的 PCI 总线上;而有些处理器系统中可能有多个 HOST 主桥,比如图1‑1中的处理器系统中就含有 HOST 主桥 X 和 HOST 主桥 Y。

PCI 总线由 HOST 主桥和 PCI 桥接器引出,HOST 主桥与主内存控制器在同一级总线上,PCI 设备可以方便地通过 HOST 主桥访问主内存,即进行 DMA 操作。

值得注意的是,PCI 设备的 DMA 操作需要与处理器系统的 Cache 进行一致性操作,当 PCI 设备通过 HOST 主桥访问主内存时,Cache 一致性模块将进行地址监听,并根据监听结果改变 Cache 的状态。

>>> 阅读全文

 

, ,

Linux 内核简介之虚拟文件系统

虚拟文件系统又称虚拟文件系统交换器(Virual Filesystem Switch ,简称 VFS)。之所以说是“虚拟”,是因为VFS是一个抽象层,其所有数据结构都是在运行以后才建立,并在卸载时删除,磁盘上并不实际存储这些数据结构。VFS 提供了操作文件 目录和对象的统一方法,即通用文件模型。但显然如果只有 VFS,系统是无法工作的,因为这些数据结构只有和实际的文件系统,如 Ext2、Minix、VFAT 等相结合才有意义。相对的, Ext2、Minix、VFAT 等则称为“具体文件系统”。具体文件系统必须提供与 VFS 定义的结构适配的例程。所以对于基于完全不同概念的文件系统如XFS或Reiser,适配会相当困难,而如 EXT2 则会有性能提升。

Linux 内核可以支持40多种文件系统,主要分为三大类 磁盘文件系统,虚拟文件系统 如 proc 文件系统 及网络文件系统。

VFS 是 Linux 内核的一个子系统,内核中的其它子系统只与 VFS 打交道,而并不与具体文件系统发生联系。对具体文件系统来说,VFS 是一个管理者,而对内核的其它子系统来说,VFS 是它们与具体文件系统的接口,整个 Linux 中文件系统的逻辑关系如图1-1所示:

VFS 提供了一个统一的接口(实际上就是 file_operatoin 数据结构,稍后介绍)。一个具体文件系统要想为 Linux 所支持,就必须按该接口编写自己的操作函数,从而将细节对内核其它子系统隐藏起来。因此对内核其它子系统以及运行在操作系统之上的用户程序而言,所有的文件系统都是透明的。实际上,要支持一种新的文件系统,主要任务就是实现这些接口函数。

总的来看 VFS 主要作用有:

>>> 阅读全文

 

, ,

Linux DRBD 模块指南

DRBD 即分布式复制块设备 (Distributed Replicated Block Device) ,是基于软件的(Software-based)、无共享的(shared-nothing)、复制存储方案,可用于在主机间镜像复制块设备(影片、分区、逻辑卷 等等)的内容。

用 DRBD 进行数据镜像有以下优点:

  • 实时。应用程序一修改设备上的数据,复制就会持续进行。
  • 透明。应用程序根本无法发觉数据存储在多个主机上。
  • 支持同步和异步。当同步数据镜像时,所有主机上完成写操作之后应用会收到通知。当异步镜像时,在本地的完成写操作之后其他主机完成写操作之前,应用就会收到通知。

DRBD 可以分为两部分:内核模块和用户空间的管理程序。

内核模块
DRBD 核心功能是通过 Linux 内核模块实现的。具体来说,DRBD 提供一个虚拟块设备的驱动程序,因此 DRBD 位于系统 I/O 栈的底部。正因如此,DRBD 非常灵活且多才多艺,是可以为任何应用程序添加高可用性的复制解决方案。

正如 Linux 内核架构所定义和构想的那样,DRBD 对其上层的组件是不可见的。因此,DRBD 无法为上层组件提供它们本就不具备的功能,比如 DRBD 无法自动检测损坏的文件系统,也无法为 ext3 或 XFS 文件系统增加 active-active 集群功能。

>>> 阅读全文

 

,

OpenWrt 教程 (二) JFFS2 文件系统

. 为什么需要 JFFS2
这一小节首先介绍了闪存相对于磁盘介质的特别之处,然后分析了将磁盘文件系统运行在闪存上的不足,同时也给出了我们使用 JFFS2 的理由。1
1.1 闪存(Flash Memory) 的特性和限制
这里所介绍的闪存的特性和限制都是从上层的文件系统的角度来看的,而不会涉及到具体的物理特性。总的来说,有两种类型的 flash memory: NOR flash 和 NAND flash. 先介绍一下这两种闪存所具有的共同特性。

A) 闪存的最小寻址单位是字节(byte),而不是磁盘上的扇区(sector)。这意味着我们可以从一块闪存的任意偏移(offset)读数据,但并不表明对闪存写操作也是以字节为单位进行的。我们会在下面的阐述中找到答案。

B) 当一块闪存处在干净的状态时(被擦写过,但是还没有写操作发生),在这块flash上的每一位(bit)都是逻辑1。

C) 闪存上的每一位(bit)可以被写操作置成逻辑0。 可是把逻辑 0 置成逻辑 1 却不能按位(bit)来操作,而只能按擦写块(erase block)为单位进行擦写操作。擦写块的大小从 4K 到128K 不等。从上层来看,擦写所完成的功能就是把擦写块内的每一位都重设置(reset)成逻辑 1。

D) 闪存的使用寿命是有限的。具体来说,闪存的使用寿命是由擦写块的最大可擦写次数来决定的。超过了最大可擦写次数,这个擦写块就成为坏块(bad block)了。因此为了避免某个擦写块被过度擦写,以至于它先于其他的擦写块达到最大可擦写次数,我们应该在尽量小的影响性能的前提下,使擦写操作均匀的分布在每个擦写块上。这个过程叫做磨损平衡(wear leveling)。

>>> 阅读全文

 

, ,

OpenWrt 教程 (一) 什么是 OpenWrt?

2002 年 12 月,Cisco/Linksys 发布了定义家用无线路由器产品形态的 WRT54G。出于成本考虑,Cisco/Linksys 使用了 Linux 作为固件而不是授权费用很高的 vXworks。根据 GPL 条款,哥伦比亚大学法学院教授 Eben Moglen 向 Cisco/Linksys 提出了开源要求,2003 年 3 月, Cisco 迫于压力公开了 WRT54G 的源代码。此后就有了一些基于 Cisco 源码的第三方路由器固件,OpenWrt 就是其中的一个,它诞生于 2004 年。

OpenWrt 最初的稳定版叫 White Russian,之后有陆续有 Kamikaze、Backfire、Attitude Adjustment等多个版本发布,而最新的 Barrier Breaker 也已经在持续开发中,据称将很快发布。在众多路由器 hack 固件中,为什么 OpenWrt 能脱颖而出呢?这是因为 OpenWrt 具有以下特点:

  • 可扩展性好。通过在线安装可以扩展所需要的功能,目前 OpenWrt 有 1000 多个可选功能包;
  • OpenWrt 是台完整的 Linux 工作站,文件系统可读可写,便于开发者学习和实践;

OpenWrt社区始终贯彻开源精神,在 OpenWrt.org 你可以找到“Wireless Freedom”的字样,其社区的组织者 Gregers Petersen 是位人类学家,专注于自由软件及相关社会学研究。因此 OpenWrt 社区聚集了大批各个方面的专家,从而使 OpenWrt 具备了如下与传统 NorFlash 嵌入式 Linux 截然不同的高级特征:

1. SquashFS 与 JFFS2 文件系统的整合形成的 overlayfs 机制
对用户而言,OpenWrt 的整个文件系统是完全动态可读写的,而其中的固件部分是用 SquashFS 实施的只读压缩文件系统,而用户所有的对文件系统的增删改都是用类似“差值”的形态存储在 JFFS2 文件系统中的,二者用 overlayfs 机制黏合,对用户完全透明。因此我们可以在文件系统中随意修改,出现问题则可像手机一样恢复出厂设置,并提供 fail-safe 模式帮助用户修复系统。

而在传统的嵌入式 Linux 里,固件是静态的,对系统做任何与可运行程序相关的变动,比如增加模块,删除应用程序,都要重新编译全部固件,并重新刷写。这种死板的传统文件系统完全阻挡了非专业爱好者进入嵌入式 Linux 这一领域。

>>> 阅读全文

 

, , , , ,

LXC (Linux Container) 初览

LXC 是 Linux Container的缩写。Linux 容器技术是一种内核虚拟化技术(也叫操作系统虚拟化),它提供了轻量级的虚拟化技术,可以在单一控制主机上同时提供多个虚拟环境(即容器)以隔离进程和资源,每个虚拟环境拥有自己的进程和独立的网络空间。在基于容器的虚拟化技术中,进程不再是个全局概念,而是从属于某个特定的容器。理想情况下,进程跟容器之间是动态关联的,进程可以在容器之间迁移。在基于容器的虚拟化技术中,容器既是资源容器,也是隔离的命名空间,它能有效地将由单个操作系统管理的资源划分到隔离的组中,以更好地在隔离的组之间平衡有冲突的资源的占用需求。从用户的角度上看,容器的运行与表现与独立拥有一台 Linux 服务器并无二致。

容器技术原理是基于操作系统内核对不同的进程提供了不同的系统视图, 它可以在本地 CPU 核心运行指令,避免了全虚拟化指令级模拟或即时编译造成的系统开销。同时也避免了准虚拟化(Para-Virtualization)和系统调用替换的复杂性。但是,容器技术强制所有客户必须使使用与控制主机(Control Host) 相同的内核,用户既不能运行其他种类操作系统,也不能运行不同的内核。图 1-1 显示了容器技术和其他虚拟化技术的不同。

容器虚拟化起源于 1982 年发布的 CHROOT 工具,这是一个特殊的基于文件子系统的容器虚拟,最早由 Sun 公司创始人 Bill Joy 开发并且作为 BSD 4.2 的组成进行发布。此后,大量的容器虚拟化技术不断涌现,主要有:

  • Solaris Zones
  • FreeBSD Jails
  • Linux VServer
  • OpenVZ

但是这些技术都没有被 Linux 内核所接受。相反 Linus 选择使用一系列新的内核特性来实现这一目标。Linux Container (LXC) 就是利用这些新特性实现的下一代容器虚拟化技术,并随着 Linux 内核而发布。

下面我们先看一下容器虚拟化的鼻祖 CHROOT 是如何工作的。

>>> 阅读全文

 

, , , , ,

了解Linux操作系统 (二)Linux内存架构

文章评分:

为了执行进程,Linux 内核会为请求的进程分配一段内存区域。进程用这段内存作为工作区来执行所请求的工作。这就像你申请了一张办公桌,你可以在桌面上摆放工作所需的纸张、文件和备忘录。不同之处是 Linux 内核采用动态的方法来分配内存空间。在内存大小通常是有限的情况下有时进程的数量会达到数万个,Linux 内核必须有效地来管控内存。在本章节中,我们会介绍内存的结构、地址分布,以及Linux是怎样有效地管理内存空间的。

物理内存与虚拟内存

如今我们面临选择 32 位系统或者 64 位系统的问题。对于企业级用户来说,最重要的区别就是虚拟内存地址是否可以超过 4GB。从性能角度来看,弄明白32 位和64 位 Linux 内核是怎么样将物理内存映射到虚拟内存是非常有意思的。

在图1-10中,你可以很明显的看出 32 位系统和 64 位系统在内存地址分配上的不同之处。关于物理内存映射到虚拟内存的详细内容已超出本文的范畴,本文将只着重介绍Linux内存结构的部分细节。

>>> 阅读全文

 

,

了解Linux操作系统 (一)进程管理

文章评分:

前言
Linux 是一种由全世界开发者共同开发的开源操作系统。其源代码可以自由获取并可以在 GNU GPL 授权下使用。有很多公司提供不同的系统发行版供用户使用,如Redhat和Novell SUSE。大部分桌面发行版都可以从网站上免费下载,但服务器版一般是需要购买的。

在过去的几年里,Linux 被世界上许多公司的数据中心所使用。如今 Linux 操作系统为科学领域和企业用户所认可。它已经成为一种多种用途的操作系统。你能在多种嵌入式设备中发现它,如:防火墙、手机或电脑主机。所以 Linux 的性能对于科学领域和企业用户来说已经成为一个热门议题。然而一个操作系统可能被用来计算全球的天气预报或者被用来运行数据库等多种用途,Linux 必须能够为各种可能的使用情境提供优良性能。大多数 Linux 发行版含有常规的调校参数来满足所有用户。

IBM 意识到作为一种操作系统,Linux 非常适合在 IBM 系统之上运行企业级应用。大多数企业应用现在都可以运行在 Linux 上,包括文件服务器、打印服务器、数据库服务器、Web服务器、以及沟通和邮件服务器。

在企业级服务器运行 Linux 时需要对其性能进行监控,在必要时需要对服务器进行调优以消除影响用户的性能瓶颈。本红皮书将介绍一些调优 Linux 的方法、监控分析服务器性能的工具、以及对于特定应用的关键性能参数。本文目的是说明怎样分析和调校 Linux 操作系统,从而为在系统上运行的各种不同应用提供优良的性能。

>>> 阅读全文

 

, , , , ,