Enterprise Just Builder

Solution for Enterprise Software Architecture

机器学习(1)数据挖掘 机器学习 和人工智能的区别

本文主要分为两部分,第一部分阐述数据挖掘(data mining)、机器学习(machine learning)和人工智能(AI)之间的区别。这三者的区别主要是目的不同,其手段(算法,模型)有很大的重叠,所以容易混淆。第二部分主要阐述以上的技能与数据科学(data science)的关系,以及数据科学(data science)和商业分析(business analytics)之间的关系。

数据挖掘 VS. 机器学习VS. 人工智能
数据挖掘 (data mining): 有目的地从现有大数据中提取数据的模式 pattern 和模型 model。
关键字:模式提取,大数据。

数据挖掘是从现有的信息(existing information)中提取数据的模式(pattern)和模型(model),即精选出最重要的信息,以用于未来机器学习和 AI 的数据使用。其核心目的是找到数据变量之间的关系。其发展出来的主要原因是大数据的发展,用传统的数据分析的方式已经无能处理那么多大量的看似不相关的数据的处理,因此需要数据挖掘技术去提取各种数据和变量之间的相互关系,从而精炼数据。

数据挖掘本质上像是机器学习和人工智能的基础,他的主要目的是从各种各样的数据来源中,提取出超集(superset)的信息,然后将这些信息合并让你发现你从来没有想到过的模式和内在关系。这就意味着,数据挖掘不是一种用来证明假说的方法,而是用来构建各种各样的假说的方法。数据挖掘不能告诉你这些问题的答案,他只能告诉你,A 和 B 可能存在相关关系,但是它无法告诉你 A 和 B 存在什么相关关系。

机器学习(machine learning): 自动地从过往的经验中学习新的知识。
关键字:关键字: 自动化,自我优化,预测,training data,推荐系统

>>> 阅读全文

, ,

将 Win32 枚举型 APIs 转换为 STL 迭代器

原文1

操作系统都有许多 API 用于存取实体集合的,比方说 Unix 的 opendir()/readdir() 函数。Win32 API 也提供了许多函数用来枚举集合内的元素,通常采用的模型无外乎下面几种:回调函数 (如 EnumChildWindows), get-first/get-next (取第一个/取下一个 比如FindFirst/NextFile), 或 get-nth (取第n个 如 RegEnumValue) — 其语义和前二者完全不同。

现在 C++ 社区正在逐步朝着符合 STL 的通用编码格式迈进,如使用容器 (序列和关联)、迭代器、泛函 (或函子或函数对象)、算法和适配器等等。这一做法的最大好处是可以采用一种通用的方法操纵不同的实体, 大大减少开发者的工作量, 同时提高健壮性、可维护性和重用。

STL 技术未被广泛运用的原因之一是除了标准库所提供的类和函数 (list, vector, for_each 等) 之外, 缺少可用的 STL 兼容库, 特别对于操作系统 API。原因之一是这涉及编程模型之间迁移转换的复杂性, 特别是对于集合和序列。本文通过将两种 Win32 枚举模型实际转换 STL 序列, 创建封装了 Win32 API 的轻量级序列类, 并提供了可按 STL 标准算法来操纵枚举实体的迭代器。

本文所演示的类是 WinSTL 库的一部分,WinSTL 则是 STLSoft 的子项目。STLSoft 是个开源组织,一直致力于将 STL 概念运用到多种技术和操作系统中去。

>>> 阅读全文

, , , ,

WDF 驱动程序开发

设备驱动程序是硬件设备连接到计算机系统的软件接口,任何设备都必须有相应的驱动程序才能在计算机系统上正常工作。设备驱动程序的优劣直接关系到整个系统的性能和稳定性,因此,设计和开发稳定高效的驱动程序具有重要意义。

WDF (Windows Driver Foundation) 是微软新一代驱动程序模型,它在 WDM (Windows Driver Model) 的基础上发展而来,支持面向对象、事件驱动的驱动程序开发,提供了比 WDM 更高层次的抽象,是高度灵活、可扩展、可诊断的驱动程序框架。WDF 框架接管了驱动和操作系统内核的大多数交互,驱动和操作系统的交互交给框架内封装的方法(函数)完成,从而对二者进行了隔离,这样驱动开发者只需专注处理硬件的行为即可。另外 WDF 还将大多数驱动中都需要处理的 PnP (即插即用)和电源管理封装进了框架,成为了公用的驱动程序功能。

WDF 可以开发内核模式驱动, 也可以开发用户模式驱动,二者采用同一套对象模型构建,即 WDF。对于内核模式对象和用户模式对象来说,WDF 是它们的父对象。换言之两者都是从 WDF 派生而来的。针对内核模式派生出来的对象称为 KMDF;针对于户模式派生出来的对象称为 UMDF。无论何种模式的框架,其内部封装的方法、执行的行为其实还是用 WDM 来完成的。

本文主要针对 KMDF 框架展开讨论。

KMDF 对象模型
KMDF 驱动程序模型支持面向对象、事件驱动。它定义了一系列的对象用于表示设备、驱动、中断等,每个对象有其相应的属性、方法和事件。驱动程序利用这些方法创建对象、设置属性和响应事件。该框架定义的主要对象有:

>>> 阅读全文

, , ,

SPB 设备和驱动简介

现在有许多文章介绍 Windows 8 操作系统层级的功能。其中之一就是支持简单外设总线 (SPB) 连接的设备。SPB 总线具有低成本、低功耗、低速度的特点,经常用于连接如传感器之类的相对简单的外设。Windows 8 支持的 SPB 设备包括 I2C 和 SPI。之前这类设备受到 BIOS 的限制而很少使用。从 Windows 8 开始,支持这些设备则成为了主流。

如果你对 SPB 总线以及如何编写 SPB 设备驱动感兴趣,可以跟随本文1来深入探讨这些话题。

SPB 总线 — 拓扑和设备枚举
和 SCSI、 SATA 和 USB 总线一样,SPB 是协议式(protocol-based ) 总线。也就是说,有一个控制器会根据总线定义的规则使用正确的协议来请求开关总线。连接到协议式总线上的设备被称为客户端设备,简称客户端。如图1-1.

SPB 总线最让人困惑的地方是如何发现和枚举总线上的设备。 SPB 总线无法动态枚举,这意味着在运行时接上 SPB 总线的设备都无法被发现。那么 Windows PnP 过程如何侦测 SPB 客户端的呢?答案很简单:哪个 SPB 设备挂在哪条 SPB 总线,这些描述被静态添加到一个表中,作为 ACPI BIOS 一部分。所以,枚举 SPB 客户端是由 ACPI 驱动而不是 SPB 控制器驱动负责的。SPB 控制器是典型的背板总线(backplane-bus )类型的设备,总被 PCI 总线驱动所枚举。详细可以参考图1-2 和图1-3。

包含该描述的 ACPI 表格被称为差异系统描述符表(Differentiated System Descriptor Table)简称 DSDT。DSDT 通常由系统集成商(一般是 OEM ) 随 ROM 一起提供的。由于 SPB 设备通常都被永久集成在系统平台上 — 大部分被焊在主板上,所以无法动态枚举不会有任何问题。 少数情况下,SPB 设备可能会被动态地接上系统(比如平板电脑的 I2C 键盘),此时设备信息仍由 ACPI BIOS 提供并由 ACPI 驱动枚举。

>>> 阅读全文

, , , , ,

 SCTP (一) 概览和消息编码

SCTP 是传输层协议,它的功能和 TCP 协议类似,并有一些独特的补充。虽然 SCTP 在互联网世界中不是很常见,但是该协议在电信网络中扮演z着重要角色。它被用做各种 SIGTRAN 协议的传输层,而且还是 EPC 的默认传输协议。

Wikipedia 上的文章 简单地介绍了 SCTP 的功能。另外 Randal Stewart, Michael Tuxen 和 Peter Lei 等著的《SCTP: What is it, and how to use it?》 也是不错的参考。本文将从网络开发者的角度来简述 SCTP ,这意味着我们要深入了解规范的某些内容。接下来我们将过一遍我最感兴趣的部分,以及相关的SCTP 规范 — RFC4960的章节引用。1

SCTP 关键术语和缩写
SCTP 协议第1.3节 和第1.4节介绍了一些关键术语和缩写。对初学者来说,最重要的是:“关联 association”、 “流 stream”和“块 chunk”。

  • 关联(Association):和 TCP 类似, SCTP 是面向连接的协议。两个点(peer)之间的逻辑连接被称为“关联”。和 TCP 不同的,两点间的 SCTP 关联可以建立在多个 IP 地址之上。如图1-1 所示, 主机 A 有三个以太网接口及三个不同的 IP 地址,主机 B 也有三个接口,但只有两个被用于关联。接口及部分关联在图中以浅蓝色表示。在建立关联的期间,每个端点的地址集将被公布,并作为下一次 POST 的主题。很重要的一点:同一个端点的 IP 地址的 SCTP 端口号是相同的 — 称为 “多方持有 multi-homing”。
  • 流(stream): 流是关联间的逻辑单向通道。具体通道数目在建立关联时确定,且每个方向上可以不同。如图1-1,从主机 A 到主机 B 的流有 7个,而从主机 B 向主机 A 的流只有 3 个。流的目的是提供逻辑通道以便按顺序传输数据/邮件。这意味着,即时流 X 中的消息丢失需要重新发送,流 Y 中的消息也不会被延迟,因为它们逻辑上独立。不过流 X 中的(丢失的消息之后)其他消息将被推迟,直到重新发送结束。这种效应称为线路头阻塞(head-of-line blocking),是 TCP 协议的主要问题之一。
  • 块(Chunk):块是 SCTP 包内的信息单元。

SCTP 规范第 1.5 节介绍了该协议的功能概述。比如如何使用流,在流中如何Section 1.5 provides functional overview of the protocol. It describes how streams are used, how in-order delivery is achieved within a stream, how data messages are acknowledged and so on.

, ,

Windows 连接管理器和 NCM 驱动

从 Windows 8 开始,微软引入了自动连接管理器,它负责查看系统的网络连接如以太网、Wi-Fi 和移动网络,从中选择最合适的网络并自动连接,同时断开其他连接。(注:Windows 会响应以太网,但不会自动管理其连接。另外:拨号上网或者虚拟网络接口如 VPN 不在其管理范围中)。1

连接管理器策略
Windows 内置了许多策略来控制连接管理器,Windows 并未提供用户界面来查看这些策略,但可利用 WcmSetProperty API 或组策略来进行配置。这些策略包括:

最少并发连接数
该策略在 Windows 8 或 8.1 中是默认打开的。如果禁用该策略,操作系统行为将与 Windows 7 类似:每个网络接口都选择其所辖的首选网络,而不管其他接口的连接状态。

如果启动该策略,Windows 会尝试用最小并发连接来提供最佳的可用网络,Windows 将保持下列连接:

  • 任何以太网
  • 当前用户会话中手动连接的任何网络
  • 连接到 Internet 的首选连接
  • 连接到活动目录域的首选网络(入域的机器)

其他的所有网络则被“软”断开,有关“软”断开请见下一节。这也用于评估未被连接的可用网络。Windows will not connect to a new network from which it would immediately soft-disconnect.

>>> 阅读全文

,

X64 寄存器、栈帧和汇编

多年以来人们一直使用 X86 汇编编写性能关键代码。随着 32位 CPU 逐渐被 64 位处理器取代,底层汇编代码也随之发生变化。本文将简单介绍 X64 汇编一些相关知识。了解 X86 汇编虽然有助于了解这种过渡,不过不是必要前提。http://www.ejb.cc/wp-admin/profile.php

X64 泛指 Intel/AMD 的 32 位 X86 指令集架构 (ISA) 的 64 位扩展。AMD 率先推出了第一代 X64 指令集。即 X86-64,后来被命名为 AMD64。Intel 的实现称为 IA-32e ,后来又改为 EMT64。这两个版本大致相同,只在一些细微处略有不兼容。详细可以参考 《Intel® 64 and IA-32 Architectures Software Developer’s Manuals》 和 《AMD64 Architecture Tech Docs》。本文中将其统称为 X64 ,以区分 Intel 64 位安腾架构 IA-64。

本文将不涉及缓存、分支预测等等与硬件相关的内容,如果读者感兴趣,可以参考本文列出的一些参考文章。1

汇编常被用来编写程序性能关键部分,虽然大部分程序员还是宁可选择好的 C++ 编译器。掌握汇编对代码调试十分有用,有时候编译器会产生错误的汇编代码,通过调试器单步执行代码可以有助于了解错误的原因;代码优化有时也会产生错误。如果手边没有源代码,你还可以通过汇编/反汇编来了解或修正手边的程序;此外如果你想深入了解语言的内部机制,比如方法 A为什么比方法 B 速度快,这时候汇编就十分必要;最后,在诊断恶意代码时,汇编也不可或缺。

架构
要学习平台汇编,首先就得了解寄存器集。

>>> 阅读全文

, ,

初窥 Windows Container 和 Docker

抽象地说所有的计算都是在一系列物理资源上(包括处理器、 内存、 磁盘、 网络等)运行某些”功能”以达成特定任务,这些计算可以是简单的数学运算,比如“1+1”,也可以是跨越多台机器的复杂应用比如 Exchange。随着时代的进步,物理资源越来越强大,结果应用程序常常只利用了物理机所提供的资源的一小部分。因而,工程师们通过创建“虚拟”资源来模拟底层物理硬件,从而使得多个应用可以并发运行 — — 每个应用使用同一物理机器的部分物理资源。

通常这些模拟技术被称为虚拟化。“虚拟化”一词会让很多人联想到虚拟机。不过“虚拟机”只是虚拟化的一种实现,而容器是另一种类型的虚拟化,也称为操作系统虚拟化。以 Linux 容器为例:在一个 Linux 操作系统中可以创建多个容器,对于运行在容器中的应用程序来说,该 Linux 容器就是一个完全隔离且独立的“操作系统”,它的磁盘就像保存原始 OS 文件的副本,内存驻留的文件和数据也和正常启动的操作系统没什么区别。要实现要做到这一点,创建容器的”宿主”机要实现一系列技术。1

首先是名称空间隔离。名称空间包含了应用程序可交互的一切资源,包括文件、 网络端口和活跃进程的列表。通过名称空间隔离,宿主可以为每个容器分配一个虚拟名称空间,其中包含只对该容器可见的资源。在此受限视图中,无论容器运行在什么权限上,它都无法访问其名称空间之外的文件,就是因为这些文件对容器不可见。容器也无法查看该容器外的应用,当然也无法与之交互,所以容器中的应用就会错认为自己独占了整个系统(其实同一时刻还可能还有成十上百个应用在运行)。

出于效率考虑,宿主操作系统的许多文件、目录以及运行服务都被不同容器所共享,并被投影到每个容器的名称空间中。只有当应用程序改动到其容器,容器才会从底层主机操作系统获得一个独立副本 — 但只是包含被改动的那部分文件。这就是 “Docker” 的“copy-on-write”优化。通过共享单个主机可以高效地部署多个容器。

其次需要宿主管控可供容器使用的主机资源。管控诸如 CPU、 RAM和网络带宽等等资源,可以确保容器获得其预期的资源且不影响主机上其他容器的性能。例可以约束某个容器使得它的 CPU 占用率不得超过 10%。这意味着即使应用程序努力尝试,它也不能获得其他 90% CPU 占用,这部分 CPU 主机可以将分配给其他容器或供自己使用。Linux 使用称为 “cgroups” 的技术来实现这种管控。当然如果同一主机上的不同容器之间是相互协作的,并允许主机根据应用的实际需求变化不断动态调整资源分配,此时就无需资源管控。

>>> 阅读全文

, ,

Windows Process 内存组织结构及重要字段解析

Windows 操作系统中的进程,实际上是用位于内核管理层(Executive)的 _EPROCESS 进程块来表示的。_EPROCESS 中不仅包含了进程相关的一些重要的数据结构,同时还包含了进程的环境变量等等东西。_EPROCESS 块的大部分数据存储在操作系统的内核空间,不过进程环境块 PEB 则是位于用户空间。这是因为 PEB 包含了一些用户可能频繁修改的数据,放在内核空间中会导致频繁的模式切换,也不利于安全。

图1-1 源自《Windows Internal》第六章里,它显示了一个完整进程的不同部分,这些部分被分别存放在系统地址空间和进程地址空间之中,以适应不同的操作模式的需要。

在内核调试模式下,我们可以用 Windbg 的 dt 命令列出 _EPROCESS 的结构:(例子基于 Windows 10 Build 10240)

WINDBG>dt nt!_eprocess
   +0x000 Pcb              : _KPROCESS
   +0x2d8 ProcessLock      : _EX_PUSH_LOCK
   +0x2e0 RundownProtect   : _EX_RUNDOWN_REF
   +0x2e8 UniqueProcessId  : Ptr64 Void
   +0x2f0 ActiveProcessLinks : _LIST_ENTRY
   +0x300 Flags2           : Uint4B
   +0x300 JobNotReallyActive : Pos 0, 1 Bit
   +0x300 AccountingFolded : Pos 1, 1 Bit
   +0x300 NewProcessReported : Pos 2, 1 Bit
   +0x300 ExitProcessReported : Pos 3, 1 Bit
   +0x300 ReportCommitChanges : Pos 4, 1 Bit
   +0x300 LastReportMemory : Pos 5, 1 Bit
   +0x300 ForceWakeCharge  : Pos 6, 1 Bit
   +0x300 CrossSessionCreate : Pos 7, 1 Bit
   +0x300 NeedsHandleRundown : Pos 8, 1 Bit
   +0x300 RefTraceEnabled  : Pos 9, 1 Bit
   +0x300 DisableDynamicCode : Pos 10, 1 Bit
   +0x300 EmptyJobEvaluated : Pos 11, 1 Bit
   +0x300 DefaultPagePriority : Pos 12, 3 Bits
   +0x300 PrimaryTokenFrozen : Pos 15, 1 Bit
   +0x300 ProcessVerifierTarget : Pos 16, 1 Bit
   +0x300 StackRandomizationDisabled : Pos 17, 1 Bit
   +0x300 AffinityPermanent : Pos 18, 1 Bit
   +0x300 AffinityUpdateEnable : Pos 19, 1 Bit
   +0x300 PropagateNode    : Pos 20, 1 Bit
   +0x300 ExplicitAffinity : Pos 21, 1 Bit
   +0x300 ProcessExecutionState : Pos 22, 2 Bits
   +0x300 DisallowStrippedImages : Pos 24, 1 Bit
   +0x300 HighEntropyASLREnabled : Pos 25, 1 Bit
   +0x300 ExtensionPointDisable : Pos 26, 1 Bit
   +0x300 ForceRelocateImages : Pos 27, 1 Bit
   +0x300 ProcessStateChangeRequest : Pos 28, 2 Bits
   +0x300 ProcessStateChangeInProgress : Pos 30, 1 Bit
   +0x300 DisallowWin32kSystemCalls : Pos 31, 1 Bit
   +0x304 Flags            : Uint4B
   +0x304 CreateReported   : Pos 0, 1 Bit
   +0x304 NoDebugInherit   : Pos 1, 1 Bit
   +0x304 ProcessExiting   : Pos 2, 1 Bit
   +0x304 ProcessDelete    : Pos 3, 1 Bit
   +0x304 ControlFlowGuardEnabled : Pos 4, 1 Bit
   +0x304 VmDeleted        : Pos 5, 1 Bit
   +0x304 OutswapEnabled   : Pos 6, 1 Bit
   +0x304 Outswapped       : Pos 7, 1 Bit
   +0x304 FailFastOnCommitFail : Pos 8, 1 Bit
   +0x304 Wow64VaSpace4Gb  : Pos 9, 1 Bit
   +0x304 AddressSpaceInitialized : Pos 10, 2 Bits
   +0x304 SetTimerResolution : Pos 12, 1 Bit
   +0x304 BreakOnTermination : Pos 13, 1 Bit
   +0x304 DeprioritizeViews : Pos 14, 1 Bit
   +0x304 WriteWatch       : Pos 15, 1 Bit
   +0x304 ProcessInSession : Pos 16, 1 Bit
   +0x304 OverrideAddressSpace : Pos 17, 1 Bit
   +0x304 HasAddressSpace  : Pos 18, 1 Bit
   +0x304 LaunchPrefetched : Pos 19, 1 Bit
   +0x304 Background       : Pos 20, 1 Bit
   +0x304 VmTopDown        : Pos 21, 1 Bit
   +0x304 ImageNotifyDone  : Pos 22, 1 Bit
   +0x304 PdeUpdateNeeded  : Pos 23, 1 Bit
   +0x304 VdmAllowed       : Pos 24, 1 Bit
   +0x304 ProcessRundown   : Pos 25, 1 Bit
   +0x304 ProcessInserted  : Pos 26, 1 Bit
   +0x304 DefaultIoPriority : Pos 27, 3 Bits
   +0x304 ProcessSelfDelete : Pos 30, 1 Bit
   +0x304 SetTimerResolutionLink : Pos 31, 1 Bit
   +0x308 CreateTime       : _LARGE_INTEGER
   +0x310 ProcessQuotaUsage : [2] Uint8B
   +0x320 ProcessQuotaPeak : [2] Uint8B
   +0x330 PeakVirtualSize  : Uint8B
   +0x338 VirtualSize      : Uint8B
   +0x340 SessionProcessLinks : _LIST_ENTRY
   +0x350 ExceptionPortData : Ptr64 Void
   +0x350 ExceptionPortValue : Uint8B
   +0x350 ExceptionPortState : Pos 0, 3 Bits
   +0x358 Token            : _EX_FAST_REF
   +0x360 WorkingSetPage   : Uint8B
   +0x368 AddressCreationLock : _EX_PUSH_LOCK
   +0x370 PageTableCommitmentLock : _EX_PUSH_LOCK
   +0x378 RotateInProgress : Ptr64 _ETHREAD
   +0x380 ForkInProgress   : Ptr64 _ETHREAD
   +0x388 CommitChargeJob  : Ptr64 _EJOB
   +0x390 CloneRoot        : _RTL_AVL_TREE
   +0x398 NumberOfPrivatePages : Uint8B
   +0x3a0 NumberOfLockedPages : Uint8B
   +0x3a8 Win32Process     : Ptr64 Void
   +0x3b0 Job              : Ptr64 _EJOB
   +0x3b8 SectionObject    : Ptr64 Void
   +0x3c0 SectionBaseAddress : Ptr64 Void
   +0x3c8 Cookie           : Uint4B
   +0x3d0 WorkingSetWatch  : Ptr64 _PAGEFAULT_HISTORY
   +0x3d8 Win32WindowStation : Ptr64 Void
   +0x3e0 InheritedFromUniqueProcessId : Ptr64 Void
   +0x3e8 LdtInformation   : Ptr64 Void
   +0x3f0 OwnerProcessId   : Uint8B
   +0x3f8 Peb              : Ptr64 _PEB
   +0x400 Session          : Ptr64 Void
   +0x408 AweInfo          : Ptr64 Void
   +0x410 QuotaBlock       : Ptr64 _EPROCESS_QUOTA_BLOCK
   +0x418 ObjectTable      : Ptr64 _HANDLE_TABLE
   +0x420 DebugPort        : Ptr64 Void
   +0x428 Wow64Process     : Ptr64 Void
   +0x430 DeviceMap        : Ptr64 Void
   +0x438 EtwDataSource    : Ptr64 Void
   +0x440 PageDirectoryPte : Uint8B
   +0x448 ImageFileName    : [15] UChar
   +0x457 PriorityClass    : UChar
   +0x458 SecurityPort     : Ptr64 Void
   +0x460 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x468 JobLinks         : _LIST_ENTRY
   +0x478 HighestUserAddress : Ptr64 Void
   +0x480 ThreadListHead   : _LIST_ENTRY
   +0x490 ActiveThreads    : Uint4B
   +0x494 ImagePathHash    : Uint4B
   +0x498 DefaultHardErrorProcessing : Uint4B
   +0x49c LastThreadExitStatus : Int4B
   +0x4a0 PrefetchTrace    : _EX_FAST_REF
   +0x4a8 LockedPagesList  : Ptr64 Void
   +0x4b0 ReadOperationCount : _LARGE_INTEGER
   +0x4b8 WriteOperationCount : _LARGE_INTEGER
   +0x4c0 OtherOperationCount : _LARGE_INTEGER
   +0x4c8 ReadTransferCount : _LARGE_INTEGER
   +0x4d0 WriteTransferCount : _LARGE_INTEGER
   +0x4d8 OtherTransferCount : _LARGE_INTEGER
   +0x4e0 CommitChargeLimit : Uint8B
   +0x4e8 CommitCharge     : Uint8B
   +0x4f0 CommitChargePeak : Uint8B
   +0x4f8 Vm               : _MMSUPPORT
   +0x5f0 MmProcessLinks   : _LIST_ENTRY
   +0x600 ModifiedPageCount : Uint4B
   +0x604 ExitStatus       : Int4B
   +0x608 VadRoot          : _RTL_AVL_TREE
   +0x610 VadHint          : Ptr64 Void
   +0x618 VadCount         : Uint8B
   +0x620 VadPhysicalPages : Uint8B
   +0x628 VadPhysicalPagesLimit : Uint8B
   +0x630 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x650 TimerResolutionLink : _LIST_ENTRY
   +0x660 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD
   +0x668 RequestedTimerResolution : Uint4B
   +0x66c SmallestTimerResolution : Uint4B
   +0x670 ExitTime         : _LARGE_INTEGER
   +0x678 InvertedFunctionTable : Ptr64 _INVERTED_FUNCTION_TABLE
   +0x680 InvertedFunctionTableLock : _EX_PUSH_LOCK
   +0x688 ActiveThreadsHighWatermark : Uint4B
   +0x68c LargePrivateVadCount : Uint4B
   +0x690 ThreadListLock   : _EX_PUSH_LOCK
   +0x698 WnfContext       : Ptr64 Void
   +0x6a0 Spare0           : Uint8B
   +0x6a8 SignatureLevel   : UChar
   +0x6a9 SectionSignatureLevel : UChar
   +0x6aa Protection       : _PS_PROTECTION
   +0x6ab HangCount        : UChar
   +0x6ac Flags3           : Uint4B
   +0x6ac Minimal          : Pos 0, 1 Bit
   +0x6ac ReplacingPageRoot : Pos 1, 1 Bit
   +0x6ac DisableNonSystemFonts : Pos 2, 1 Bit
   +0x6ac AuditNonSystemFontLoading : Pos 3, 1 Bit
   +0x6ac Crashed          : Pos 4, 1 Bit
   +0x6ac JobVadsAreTracked : Pos 5, 1 Bit
   +0x6ac VadTrackingDisabled : Pos 6, 1 Bit
   +0x6ac AuxiliaryProcess : Pos 7, 1 Bit
   +0x6ac SubsystemProcess : Pos 8, 1 Bit
   +0x6ac IndirectCpuSets  : Pos 9, 1 Bit
   +0x6ac InPrivate        : Pos 10, 1 Bit
   +0x6b0 DeviceAsid       : Int4B
   +0x6b8 SvmData          : Ptr64 Void
   +0x6c0 SvmProcessLock   : _EX_PUSH_LOCK
   +0x6c8 SvmLock          : Uint8B
   +0x6d0 SvmProcessDeviceListHead : _LIST_ENTRY
   +0x6e0 LastFreezeInterruptTime : Uint8B
   +0x6e8 DiskCounters     : Ptr64 _PROCESS_DISK_COUNTERS
   +0x6f0 PicoContext      : Ptr64 Void
   +0x6f8 TrustletIdentity : Uint8B
   +0x700 KeepAliveCounter : Uint4B
   +0x704 NoWakeKeepAliveCounter : Uint4B
   +0x708 HighPriorityFaultsAllowed : Uint4B
   +0x710 EnergyValues     : Ptr64 _PROCESS_ENERGY_VALUES
   +0x718 VmContext        : Ptr64 Void
   +0x720 Silo             : Ptr64 _ESILO
   +0x728 SiloEntry        : _LIST_ENTRY
   +0x738 SequenceNumber   : Uint8B
   +0x740 CreateInterruptTime : Uint8B
   +0x748 CreateUnbiasedInterruptTime : Uint8B
   +0x750 TotalUnbiasedFrozenTime : Uint8B
   +0x758 LastAppStateUpdateTime : Uint8B
   +0x760 LastAppStateUptime : Pos 0, 61 Bits
   +0x760 LastAppState     : Pos 61, 3 Bits
   +0x768 SharedCommitCharge : Uint8B
   +0x770 SharedCommitLock : _EX_PUSH_LOCK
   +0x778 SharedCommitLinks : _LIST_ENTRY
   +0x788 AllowedCpuSets   : Uint8B
   +0x790 DefaultCpuSets   : Uint8B
   +0x788 AllowedCpuSetsIndirect : Ptr64 Uint8B
   +0x790 DefaultCpuSetsIndirect : Ptr64 Uint8B

也可以用 dt nt!_eprocess –r1 命令来展开成为下一级的结构体的定义。

Linux和Windows设备驱动架构比较

本文将带你考察最为广泛使用的 Windows 和 Linux 操作系统的设备驱动架构的差异。文章将首先阐述比较这两个平台上实现设备驱动所需的组件,然后讨论实现驱动程序的过程,包括如何对内核缓冲区执行 I/O 操作等等。最后我们还将了解这两个操作系统所提供的开发环境和基础工具。1

1.引言
现代操作系统一般都包含多个模块,如内存管理器、进程调度器、硬件抽象层和安全管理器等等。这里提供一些参考资料以方便你进一步了解这两种操作系统的内核:关于 Windows 内核的细节,可翻阅 Russinovich 著的《Windows Internal》一书;而 Linux 内核则可以参考 Rusling 的《The Linux Kernel》或者 Beck et al 等合著的《Linux Kernel Internal》。内核可视为一个黑盒,它知道如何去和市面现有的或将要推出的各种设备交互。能否让内核内建支持所有市面上的已知设备呢?这是有可能实现的,但没有实际意义,因为这会无谓地消耗过多的系统资源。

内核模块化
内核无法在创建伊始就预见到要如何与尚未面世的新设备交互。现代操作系统的内核允许在运行时添加设备驱动模块来扩展系统功能,该模块实现的功能使得内核可以与特定的某种新设备交互。这些模块通常都会实现一个例程供内核在加载模块时调用,此外还有一个例程供移除模块时调用。模块还会实现其他各种不同的例程以便实现 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》,该书可免费获取。

>>> 阅读全文

, , , , ,

理解 ACPI (一) ACPI 简介及加电过程

在引入高级配置和电源接口 (ACPI — Advanced Configuration and Power Interface) 之前, 高级电源管理 (APM) BIOS 被广泛用于电源管理。在 APM 中,大部分的电源管理控制逻辑都驻留在 APM BIOS 代码中。支持 APM 的操作系统通过固定的 BIOS API 与 APM BIOS 进行通信,这些 API 提供了 BIOS 功能的基本访问。支持 APM 的操作系统必须定期轮询 APM 以处理 APM 相关事件。

APM 存在着以下三个缺陷: 首先,除非供应商提供专有程序,否则很多 APM 功能都要在操作系统启动前,进入 BIOS 菜单来配置,比如设置显示器关闭前的空闲时间。而且 APM 电源管理配置的具体策略是由 BIOS 供应商设定的,比如某 APM BIOS 的策略是在关闭显示器的同时降低 CPU 时钟频率或休眠网卡等设备,如果不想这么做,就必须修改 BIOS。 其次,APM 是 BIOS 级别的代码,运行在操作系统之外,因此开发和调试 APM 代码都十分困难,更糟糕的是用户只能通过重刷 ROM 的方式来解决 APM 的错误,而重刷 BIOS 相当危险,一旦发生错误,系统就再无法启动了。最后,由于 APM 是各个供应商专有的,为相同的功能而进行的重复开发投入是种巨大浪费。

不同于 APM 直接基于 BIOS 的管理方式,ACPI 中不再由 BIOS 代码来作出决策,而是通过操作系统内核来统一管理所有设备,从而解决了 APM 配置机制的局限性,换句话说,ACPI 允许操作系统直接对电源和散热进行管理,还允许系统硬件产生的 Hot-Plug 事件,让操作系统从用户的角度上直接支配即插即用设备。因而 ACPI 比其他机制更加灵活。

ACPI 主要提供下列功能:1

  • 系统电源管理(System power management):ACPI 提供了让系统作为一个整体进入或离开睡眠状态的机制,让设备唤醒系统。
  • 设备电源管理(Device power management):ACPI 表描述了电源信息(包括主板设备、设备电源状态以及设备所连接的电源层– Power Planes) 和让设备进入低功耗状态的控制信息,这样操作系统就可根据资源占用来控制设备进入低功耗状态。
  • 处理器电源管理(Processor power management):当操作系统处于空闲且非睡眠状态,可以通过 ACPI 提供的命令让处理器进入低功耗状态。
  • 设备和处理器性能管理(Device and processor performance management):操作系统在工作时可以根据 ACPI 的定义,让设备和处理器进入不同的性能状态
  • 配置/即插即用(Configuration/Plug and Play):ACPI 指定了用来枚举和配置主板设备的信息,这些信息按层次结构排列,当发生诸如 docking/undocking 之类的事件时,操作系统就可准确知道该事件影响了哪个设备。
  • 系统事件(System Event): ACPI 提供了通用的事件机制操作用于处理如散热、电源管理、坞站或设备的插拔等事件。
  • 电池管理(Battery management):兼容 ACPI 的电池设备需要具有智能电池子系统接口(Smart Battery subsystem interface)或者控制型电池接口(Control Method Battery interface),前者通过嵌入式控制器的接口控制,后者则完全由 AML 控制方法进行操控。
  • 温度管理(Thermal management):ACPI 允许 OEM 自由定义散热温度区间。
  • 嵌入式控制器(Embedded Controller):ACPI 提供了标准接口让操作系统和嵌入式控制器进行通讯。
  • SMBus 控制器(SMBus Controller): ACPI 提供了标准接口让操作系统和 SMBus 进行通讯。

当然为此操作系统内核中要添加额外的 ACPI 支持。支持 ACPI 的操作系统就可以叫做 OSPM (Operating System-directed configuration and Power Management) 。 支持 OSPM 的至少要求实现:

>>> 阅读全文

, , , ,

Windows CSRSS 详解 (1) 基础概念

微软之所以引入 “Windows 环境子系统” 这一概念,其理念是为了用户程序提供一个严格定义的原生函数子集。这是因为 Windows 操作系统被设计成同时支持原生 Windows 和 POSIX 类型的可执行程序(在 Windows 10 Red Stone 中还新添加了 Windows Subsystem for Linux 子系统),因此对于每一类应用,开发者必须区隔其所调用的 API。每个环境子系统通常包含两个主要部分:1

  • 子系统进程:一个正常的 ring-3 级应用程序,负责处理某些子系统特定的功能。
  • 子系统 DLL: 特定子系统专用的系统类库集,是额外添加在用户程序与原生系统调用间的调用层。

事实上 Windows 子系统 — — 也称为 CSRSS (客户端/服务器运行时子系统 Client/Server Runtime Subsystem) 是系统强制的执行环境,换句话说,如果没有没有 CSRSS.exe 在后台运行, Windows 不能正确工作。由于 CSRSS 所绑定的职责,该子系统对每个 Windows 都是必须的,包括服务器版本 (它可以不处理交互式用户会话)。另一方面,POSIX (psxss.exe) 和 Windows Subsystem for Linux 属于可选子系统 — — 因此,只在需要才启动相关进程。

子系统的启动信息被保存在注册表键 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems 下面。默认的启动信息配置如下:

  • 名称: Debug 类型: REG_EXPAND_SZ 数据:
  • 名称: Kmode 类型: REG_EXPAND_SZ 数据: \SystemRoot\System32\win32k.sys
  • 名称: Optional 类型: REG_MULTI_SZ 数据: Posix
  • 名称: Posix 类型: REG_EXPAND_SZ 数据: %SystemRoot%\system32\psxss.exe
  • 名称: Required 类型: REG_MULTI_SZ 数据: Debug Windows
  • 名称: Windows 类型: REG_EXPAND_SZ 数据: %SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,20480,768 Windows=On ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ServerDll=sxssrv,4 ProfileC

大多数人对支持 Windows API 的子系统 DLL 都有所耳闻 — 即 kernel32.dll、 user32.dll、 gdi32.dll、 advapi32.dll 等等,无数的 Windows 软件开发者在日常工作中都会用到它们。而对于 POSIX 子系统来说,只需用到 psxdll.dll 这一个模块就可以实现所需的 Unix API。

此外,每一个进程都会与某个特定的子系统关联,该属性是由链接器在编译过程中设置的,并保存在 PE 结构的相关字段中:

>>> 阅读全文

, ,

Xperf 高手训练营 (1): NetTCPPortSharing 和 NLA Services 导致系统启动缓慢

本系列文章将通过一些现实生活中的例子来展示如何用 Xperf 工具来诊断一些常见的性能问题,并如何实现系统优化的。1

我们的第一个案例是某台笔记本花了2分钟才能显示出正常的桌面。要加速启动速度,我们必须先了解问题出在哪里。所以首先需要抓取系统痕迹(trace),xbootmgr 工具适用于系统开关机的场景,其命令如下:

xbootmgr -trace boot -traceFlags Latency+DISPATCHER -postBootDelay 120 -stackWalk Profile+ProcessCreate+CSwitch+ReadyThread+Mark+SyscallEnter+ThreadCreate

注意这里的 -stackwalk 开关。 stackwalking 使得我们可以在痕迹中查看模块以及函数调用。对于 64位机器,在收集痕迹文件之前,须先禁止执行换页以防部分内核被换出。你可以执行以下命令来达到这一目的。

Reg.exe add “HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management” -v DisablePagingExecutive -d 0x1 -t REG_DWORD -f

收集好痕迹文件,接着打开 Performance Analyzer。Performance Analyzer (又称 xperfview) 是用来分析 XPERF 痕迹的工具。它是 Windows 性能工具箱(Windows Performance Toolkit) 中的利器,该工具箱是 Windows SDK 的一部分。

, ,

CPU C-State 详解

如果你对计算机电源管理方面有所了解,一定会接触到 S-States、C-States 和 P-States 这三种工作状态。其中S-States (Sleeping states)指系统睡眠状态 ,由 ACPI 规定,C-States(CPU Power state) 则是 CPU 电源状态,而 P-States (CPU Performance states) 则指 CPU 性能状态。当然除了这三种外,还有 G-States(全局状态)和 D-States (设备状态)。

S-States 很好理解,就是用户手动点击“睡眠”,或者达到一定的待机时间(由系统电源管理设置而定)进入睡眠状态,S0 就是指正常运作。而 C-States 和P-States 看起来也很类似,都会调节处理器的核心电压、电流以及频率,因此经常被混淆。我们通过图1-1 来梳理一下上面这三种状态的关系。

S-States 中的 S0 指非睡眠状态,即系统正常运作状态或待机状态(idle)。只有在 S0 状态下,C-States 才会存在。同样的,C0 代表 CPU 正常工作状态,而P-States 正是处理器正常运作时的状态,所以 P-States 只存在于 C0 状态下。

因此简单来说,P-States 是根据系统的负载情况调节处理器核心电压和频率,处理器仍在运作当中;而 C-States 则是改变处理器各个部分的状态,包括核心、缓存、总线以及各种后来集成进来的模块,此时处理器应该是处于工作或待机状态。我们日常使用电脑的时候,系统就是频繁地在这些状态下切换,以达到提高续航和降低功耗的目的。1

C-States 的 11 个工作状态
目前 C-States 有以下这11个状态:

>>> 阅读全文

, ,

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.

>>> 阅读全文

Previous Posts