[转]Windows NT 内核基本结构
转自:http://spinlock.blog.51cto.com/607469/174696
作者:kevx
尽管大部分人每天在Windows系统上工作学习娱乐,但是对于其内核结构很多人仍然是不了解的。一方面是由于其内核源代码不开源,另一方面则是由于相关资料的奇缺。我大二基本上花了一学期来学习和探究NT内核。虽然不敢说自己对其有很深入的了解,但至少其基本结构还算是清楚的。但是我毕竟才学有限,肯定会有不完善的地方,还请各位不吝赐教。
目前微软所有的主流操作系统均是基于NT内核,比如:Windows 2000/XP/Server 2003(基于NT5)
Windows Vista (基于NT6)
Windows 7(基于NT6.1, 我没装过Win7,不过据说是这样的)
微软早期希望把NT做成一个纯微内核结构,关于微内核和单一内核的区别,各位如有不清楚的,可以去网上搜索一下。后来为了提高图形子系统的性能,避免大量的内核态和用户态切换,微软便将其移入内核之中,使其成为内核一部分(类似的还有后来的DirectX技术)。由此可见,NT并不是一个完全的微内核,它也具有单一内核的某些特征。
NT内核具有以下几个特征(摘自Undocumented Windows NT)
Portability (可移植性)
如你所知,Windows NT 可以运行在多种平台上,即 Intel、MIPS、Power PC 和 DEC Alpha。众多厂商都为 Windows NT 的可移植性做出了贡献。 其中最为重要的因素可能是其实现所使用的语言。Windows NT 大部分是用 C 语言编写的,也有一部分用的是 C++。 平台相关的汇编语言只在必需的地方才用到。Windows NT 团队还将操作系统中硬件相关的部分与其它部分隔离开,单独放进了 HAL.DLL。 如此一来,Windows NT 中与硬件无关的部分的代码就可以用 C 之类的高级语言来编写,也因此可以很容易地移植到各种平台。
如你所知,Windows NT 可以运行在多种平台上,即 Intel、MIPS、Power PC 和 DEC Alpha。众多厂商都为 Windows NT 的可移植性做出了贡献。 其中最为重要的因素可能是其实现所使用的语言。Windows NT 大部分是用 C 语言编写的,也有一部分用的是 C++。 平台相关的汇编语言只在必需的地方才用到。Windows NT 团队还将操作系统中硬件相关的部分与其它部分隔离开,单独放进了 HAL.DLL。 如此一来,Windows NT 中与硬件无关的部分的代码就可以用 C 之类的高级语言来编写,也因此可以很容易地移植到各种平台。
Extensibility(可扩展性)
Windows NT 具有很高的可扩展性,但因为缺少文档,其可扩展的特性却极少得到发掘。未公开的特性的名单中,子系统首当其冲。子系统在操作系统中提供了多种操作系统接口。只需添加新的子系统程序就可以为 Windows NT 扩展新的操作系统接口,但是对于公开添加新子系统过程的要求微软却一直打马虎眼。
Windows NT 的内核是高可扩展的,因为可以将内核模块作为驱动程序动态加载。对于 Windows NT,微软提供了足够的文档来编写硬件设备驱动——即硬盘驱动、网卡驱动、磁带机驱动等等。在 Windows NT 下还可以编写不控制设备的驱动程序。甚至连文件系统也是作为驱动程序加载的。
Windows NT 的可扩展性的另一个例子就是系统调用接口的实现。 开发者要修改操作系统行为,一般都需要钩挂或添加系统调用。 Windows NT 的开发团队实际了良好的系统调用接口以方便钩挂和添加系统调用。但是微软还是没有公开这些机制。
Windows NT 具有很高的可扩展性,但因为缺少文档,其可扩展的特性却极少得到发掘。未公开的特性的名单中,子系统首当其冲。子系统在操作系统中提供了多种操作系统接口。只需添加新的子系统程序就可以为 Windows NT 扩展新的操作系统接口,但是对于公开添加新子系统过程的要求微软却一直打马虎眼。
Windows NT 的内核是高可扩展的,因为可以将内核模块作为驱动程序动态加载。对于 Windows NT,微软提供了足够的文档来编写硬件设备驱动——即硬盘驱动、网卡驱动、磁带机驱动等等。在 Windows NT 下还可以编写不控制设备的驱动程序。甚至连文件系统也是作为驱动程序加载的。
Windows NT 的可扩展性的另一个例子就是系统调用接口的实现。 开发者要修改操作系统行为,一般都需要钩挂或添加系统调用。 Windows NT 的开发团队实际了良好的系统调用接口以方便钩挂和添加系统调用。但是微软还是没有公开这些机制。
Compatibility(兼容性)
长久以来,向下兼容性都是 Intel 处理器和微软操作系统的一大特征,也是这两位巨人成功的关键。Windows NT 必须能运行 DOS、Win16 和 OS/2 的程序。兼容性是 Windows NT 开发团队使用子系统概念的另一个原因。除二进制兼容之外(执行不同格式的可执行文件),Windows NT 还为符合 POSIX 的程序提供了源代码级的兼容。增强兼容性的其他方面还表现在除自己本身的 NTFS 外,Windows NT 支持其它的文件系统,如 DOS 的 FAT 和 OS/2 的 HPFS。
长久以来,向下兼容性都是 Intel 处理器和微软操作系统的一大特征,也是这两位巨人成功的关键。Windows NT 必须能运行 DOS、Win16 和 OS/2 的程序。兼容性是 Windows NT 开发团队使用子系统概念的另一个原因。除二进制兼容之外(执行不同格式的可执行文件),Windows NT 还为符合 POSIX 的程序提供了源代码级的兼容。增强兼容性的其他方面还表现在除自己本身的 NTFS 外,Windows NT 支持其它的文件系统,如 DOS 的 FAT 和 OS/2 的 HPFS。
Maintainability(可维护性)
Windows NT 的代码量很大,维护着些代码的工作量也相当大。NT 的开发团队通过使用面向对象的设计实现了高可维护性。再有,将操作系统的功能分成各个层也提高了可维护性。最上面的一层,也就是用户见到的操作系统层面,是子系统层。子系统提供系统调用接口来为外界提供应用程序编程接口。在系统调用接口层之下的是 NT 的 executive,executive 又建立在内核之上,而内核又依赖于硬件抽象层(HAL),硬件抽象层与硬件直接通讯。
NT 的开发团队所选的编程语言也与 Windows NT 的可维护性有关。正如我们前面提到的,整个操作系统都是用 C 和 C++ 来编写的,只有极少数不用不行的地方用了汇编语言。
Security(安全性)
Windows NT 是一个安全的操作系统,是因为它有以下几点特征:用户在使用系统之前必须先登陆。 系统中的资源都被视为对象,而每一个对象都相应由一个安全描述符。安全描述符有一个安全列表来指示那些用户可以访问该对象。
尽管有这些,要是没有一个安全的文件系统,操作系统也不能说是安全的。 DOS 时的 FAT 文件系统没有预见到任何的安全问题,其作为一个单用户的系统,也不用防范安全问题。
为了克服此缺陷,Windows NT 团队推出了一种新的文件系统,这种文件系统基于 OS/2 的文件系统 HPFS。这种新的 Windows NT 的自有文件系统叫 NTFS。它支持访问控制,用户可以为 NTFS 下创建的文件或目录指定访问权限,NTFS 只允许有访问权限的进程访问该文件或目录。
Multiprocessing(多进程)
Windows NT 支持对称多处理,Windows NT 的工作站版本可以支持两个处理器,服务器版可以支持到4个。为支持多处理,操作系统需要特殊的同步机制。在单处理器系统中,通过禁用中断,临界区中的代码执行时不会被打断。这对于维护内核数据结构的完整性来说是必需的。在多处理器环境下,就不可能在所有的处理器上都禁用中断。在多处理环境中,Windows NT 使用自旋锁来保护内核数据结构。
注:多处理可分为对称的和非对称的。在非对称多处理中,有一个处理器为主处理器,其它的处理器都为从处理器。只有主处理器运行在内核模式,其它从处理器都只运行在用户线程。只要运行在用户线程的从处理器一调用系统服务,主处理器就接管此线程并执行所需的内核服务。调度程序,一个内核程序,之运行在主处理器上。因此,主处理扮演者调度员的角色,将用户模式线程分派给从处理器。很自然,与所有处理器都可在内核或用户模式运行的对称多处理相比,主处理器负担很重,系统不均衡。
International Language Support(国际化语言支持)
如今众多的 PC 用户都使用英语之外的其它语言。与这些用户能很好交互的关键就是使操作系统能支持用户们的语言。Windows NT 通过使用 Unicode 标准的字符集实现了这一目标。Unicode 标准规定了一个16位的字符集,而ASCII 使用的是8位字符集。 Unicode 的前256个字符的编码与 ASCII 的相同。这就为非拉丁语的语言留出了充足的空间。Win32 API 能接受 Unicode 和 ASCII 两种字符集,而 Windows NT 的内核则只能使用 Unicode。尽管应用程序程序员可以不去了解 Unicode,但驱动程序的开发者必须熟悉 Unicode,因为内核接口函数只接受 Unicode 字符串而且驱动的入口点都用的是 Unicode。
Windows NT 从 MACH 操作系统那里借用了核心体系,MACH 操作系统是在卡耐基梅隆大学开发的。MACH 操作系统的基本理念就是通过将复杂的操作系统功能交给用户级进程而将内核减至最小。这种客户机-服务器的操作系统体系还有另外一个目的:允许在同一操作系统上使用多种 APIs。通过在服务器进程中实现 APIs 就可以做到。
MACH 操作系统的内核提供了非常简单的一组接口函数。服务器进程使用这组接口函数实现出某种 API 来提供一组更复杂的接口函数。Windows NT 从 MACH 那里借用了这个理念。Windows NT 中的服务器进程被称作子系统。模块化和结构化的程序设计都是优秀软件管理的原则,NT 选择使用客户机-服务器的体系结构显示了它对这种原则的服从。Windows NT 本可以将所需的 APIs 在内核实现,也可以在内核上加上不同的层来实现不同的 APIs。出于维护性和扩展性的目的,NT 团队选择了子系统的办法。
Windows NT 的代码量很大,维护着些代码的工作量也相当大。NT 的开发团队通过使用面向对象的设计实现了高可维护性。再有,将操作系统的功能分成各个层也提高了可维护性。最上面的一层,也就是用户见到的操作系统层面,是子系统层。子系统提供系统调用接口来为外界提供应用程序编程接口。在系统调用接口层之下的是 NT 的 executive,executive 又建立在内核之上,而内核又依赖于硬件抽象层(HAL),硬件抽象层与硬件直接通讯。
NT 的开发团队所选的编程语言也与 Windows NT 的可维护性有关。正如我们前面提到的,整个操作系统都是用 C 和 C++ 来编写的,只有极少数不用不行的地方用了汇编语言。
Security(安全性)
Windows NT 是一个安全的操作系统,是因为它有以下几点特征:用户在使用系统之前必须先登陆。 系统中的资源都被视为对象,而每一个对象都相应由一个安全描述符。安全描述符有一个安全列表来指示那些用户可以访问该对象。
尽管有这些,要是没有一个安全的文件系统,操作系统也不能说是安全的。 DOS 时的 FAT 文件系统没有预见到任何的安全问题,其作为一个单用户的系统,也不用防范安全问题。
为了克服此缺陷,Windows NT 团队推出了一种新的文件系统,这种文件系统基于 OS/2 的文件系统 HPFS。这种新的 Windows NT 的自有文件系统叫 NTFS。它支持访问控制,用户可以为 NTFS 下创建的文件或目录指定访问权限,NTFS 只允许有访问权限的进程访问该文件或目录。
Multiprocessing(多进程)
Windows NT 支持对称多处理,Windows NT 的工作站版本可以支持两个处理器,服务器版可以支持到4个。为支持多处理,操作系统需要特殊的同步机制。在单处理器系统中,通过禁用中断,临界区中的代码执行时不会被打断。这对于维护内核数据结构的完整性来说是必需的。在多处理器环境下,就不可能在所有的处理器上都禁用中断。在多处理环境中,Windows NT 使用自旋锁来保护内核数据结构。
注:多处理可分为对称的和非对称的。在非对称多处理中,有一个处理器为主处理器,其它的处理器都为从处理器。只有主处理器运行在内核模式,其它从处理器都只运行在用户线程。只要运行在用户线程的从处理器一调用系统服务,主处理器就接管此线程并执行所需的内核服务。调度程序,一个内核程序,之运行在主处理器上。因此,主处理扮演者调度员的角色,将用户模式线程分派给从处理器。很自然,与所有处理器都可在内核或用户模式运行的对称多处理相比,主处理器负担很重,系统不均衡。
International Language Support(国际化语言支持)
如今众多的 PC 用户都使用英语之外的其它语言。与这些用户能很好交互的关键就是使操作系统能支持用户们的语言。Windows NT 通过使用 Unicode 标准的字符集实现了这一目标。Unicode 标准规定了一个16位的字符集,而ASCII 使用的是8位字符集。 Unicode 的前256个字符的编码与 ASCII 的相同。这就为非拉丁语的语言留出了充足的空间。Win32 API 能接受 Unicode 和 ASCII 两种字符集,而 Windows NT 的内核则只能使用 Unicode。尽管应用程序程序员可以不去了解 Unicode,但驱动程序的开发者必须熟悉 Unicode,因为内核接口函数只接受 Unicode 字符串而且驱动的入口点都用的是 Unicode。
Windows NT 从 MACH 操作系统那里借用了核心体系,MACH 操作系统是在卡耐基梅隆大学开发的。MACH 操作系统的基本理念就是通过将复杂的操作系统功能交给用户级进程而将内核减至最小。这种客户机-服务器的操作系统体系还有另外一个目的:允许在同一操作系统上使用多种 APIs。通过在服务器进程中实现 APIs 就可以做到。
MACH 操作系统的内核提供了非常简单的一组接口函数。服务器进程使用这组接口函数实现出某种 API 来提供一组更复杂的接口函数。Windows NT 从 MACH 那里借用了这个理念。Windows NT 中的服务器进程被称作子系统。模块化和结构化的程序设计都是优秀软件管理的原则,NT 选择使用客户机-服务器的体系结构显示了它对这种原则的服从。Windows NT 本可以将所需的 APIs 在内核实现,也可以在内核上加上不同的层来实现不同的 APIs。出于维护性和扩展性的目的,NT 团队选择了子系统的办法。
Windows NT 中有两种子系统: integral subsystems 和 environment subsystems。Integral subsystems,如安全管理子系统,完成基本的操作系统任务。 Environment subsystems 则使得一台 Windows NT 机器能使用不同种类的 APIs。Windows NT 的子系统能支持以下的 APIs:
Win32 子系统。Win32 子系统提供 Win32 API。使用 Win32 API 的应用程序可以运行在微软 提供的所有平台上—
WOW 子系统。Windows on Windows (WOW) 子系统提供了对 16-bit Windows 应用程序的兼容,使得 Win16 的应用程序可以在 Windows NT 上运行。只要没有使用 Windows NT 不支持的未公开函数,这些应用程序都可以运行。
NTVDM 子系统。NT Virtual DOS Machine (NTVDM) 提供了一个基于文本的环境,DOS 程序可以在这个环境中运行。
OS/2 子系统。OS/2 子系统能运行 OS/2 应用程序。WOW、NTVDM 和 OS/2 都只能用在 Intel 平台上,因为他们都对应用程序提供二进制兼容性。而用于一种处理器的可执行文件或二进制文件就不能用在另一种处理器上,因为处理器间的机器指令格式不同。
POSIX 子系统。POSIX 子系统提供符合 POSIX 1003.1 标准的 API。
应用程序并不知道所调用的 API 是由相应的子系统处理的。这种隐藏是通过每种子系统各自的客户端 DLL 来实现的。这种 DLL 将 API 调用转换为本地过程调用(local procedure call,LPC)。本地过程调用类似于联网的 UNIX 上的远程过程调用(RPC)。使用 RPC,客户应用程序可以调用运行在网络上另一台机器上的服务器进程。 LPC 对运行在同一台计算机上的客户机与服务器进行了优化。
NT内核主要包含以下几个重要文件:
Ntoskrnl.exe(或者Ntkrnlpa.exe)
HAL.Dll
NTDll.Dll
Win32k.Sys
NT内核的核心是NT EXECUTIVE。对应的文件是Ntoskrnl.exe。如果是机器是多处理器的,则是Ntkrnlpa.exe。非常可笑的是,这个文件可以直接删除,其后果就是重启后Windows无法启动,甚至连滚动条都看不到。该文件只有2MB左右的大小,但可谓是麻雀虽小五脏俱全,它作为整个Windows中最核心的部分,向外界提供了复杂的接口。
与之相辅相成的是HAL.Dll文件,即Hardware Abstraction Layer 硬件抽象层 。它直接与机器的硬件打交道,将硬件的差异对其之上的层隐藏起来。Windows NT 是一个有高可移植性的操作系统,运行在多种平台上。HAL.DLL 包含的代码向核心的其它部分隐藏了处理器和机器相关的细节。因此平台之间只有 HAL.DLL 不同,剩下的使用 HAL 接口的核心代码都有很高的可移植性。
NTDll.Dll模块。导出了大部分的Native API函数,提供了由用户态至内核态的切换的功能。做过Windows平台开发的人都知道,Windows API主要由Kernel32.Dll, User32.Dll, GDI32.Dll构成。其实对WindowsAPI的调用最终会被转接到NTDll。即所谓Native API,命名上基本上就是在原API前面加上Nt或者Zw(比如CreateFile就变成了NtCreateFile)。而Kernel32.Dll, User32.Dll, GDI32.Dll三个文件则组成了Win32子系统,它们本身不实现API,它导出的函数被称为stub 函数(尽管名称上看起来很迷惑人)
Win32K.sys模块。实现了Windows的图形处理部分。USER32 和 GDI32 使用系统调用接口来调用 WIN32K.SYS 中的服务。由于其工作与内核态,所以具有很高的性能,这也成就了Windows系统的强大的图形处理能力。