[DriverCategory]
[Signature("/pci/03/00/5333/8811")]
class S3TrioConfig : DriverCategoryDeclaration
{
// Hardware resources from PCI config
[IoMemoryRange(0, Default = 0xf8000000, Length = 0x400000)]
IoMemoryRange frameBuffer;
// Fixed hardware resources
[IoFixedMemoryRange(Base = 0xb8000, Length = 0x8000)]
IoMemoryRange textBuffer;
[IoFixedMemoryRange(Base = 0xa0000, Length = 0x8000)]
IoMemoryRange fontBuffer;
[IoFixedPortRange (Base = 0x
IoPortRange control;
[IoFixedPortRange(Base = 0x4ae8, Length = 0x02)]
IoPortRange advanced;
[IoFixedPortRange(Base = 0x9ae8, Length = 0x02)]
IoPortRange gpstat;
// Channels
[ExtensionEndpoint(typeof(ExtensionContract.Exp))]
TRef<ExtensionContract.Exp:Start> iosys;
[ServiceEndpoint(typeof(VideoDeviceContract.Exp))]
TRef<ServiceProviderContract.Exp:Start> video;
...
}
DriverCatogory和Signature这两个属性声明此模块是PCI音频设备中的某个指定类的驱动程序。属性DriverCatogory表示实现特定硬件设备驱动程序的应用程序类别。其余的分类包括ServiceCatogory——实现软件服务的应用程序类别和WebAppCategory——Singularity’s Cassini Web server的扩展类别。
属性IoMemoryRange声明frameBuffer来自于设备的PCI配置空间的第一个入口点。这个入口点是在配置硬件和设置诸如内存区域的尺寸,必须与属性中的值兼容之类的硬件参数时被发现的。IoFixedMemoryRange和IoFixedPortRange这两个属性分别指明一个设备需要固定范围的地址空间用于内存映射访问和需要固定范围的I/O端口用于访问设备寄存器。
属性ServiceEndpoint声明一个通讯信道和接受来自客户端的输入绑定请求的本地端点。章节
5.2.2
编译
在编译的时候,C#编译器将自定义属性转换成MSIL二进制码。这个转换是使用MSIL元数据访问库进行的。MSIL元数据访问库是能解析MSIL二进制码中的指令和元数据流的专用工具。
在链接的时候,mkmani这个工具读取自定义属性以创建应用程序清单。应用程序清单是一个XML文件,它列举了应用程序的组件、输出和依赖性。
如下所示的XML文件包含了S3Trio64设备驱动程序清单信息的一部分。
<manifest>
<application identity="S3Trio64" />
<assemblies>
<assembly filename="S3Trio64.exe" />
<assembly filename="Namespace.Contracts.dll" version="
/>
<assembly filename="Io.Contracts.dll" version="
<assembly filename="Corlib.dll" version="
<assembly filename="Corlibsg.dll" version="
<assembly filename="System.Compiler.Runtime.dll"
version="
<assembly filename="Microsoft.SingSharp.Runtime.dll"
version="
<assembly filename="ILHelpers.dll" version="
<assembly filename="Singularity.V1.ill" version="
</assemblies>
<driverCategory>
<device signature="/pci/03/00/5333/8811" />
<ioMemoryRange index="0" baseAddress="0xf8000000"
rangeLength="0x400000" />
<ioMemoryRange baseAddress="0xb8000" rangeLength="0x8000"
fixed="True" />
<ioMemoryRange baseAddress="0xa0000" rangeLength="0x8000"
fixed="True" />
<ioPortRange baseAddress="0x
<ioPortRange baseAddress="0x4ae8" rangeLength="0x2" fixed="True" />
<ioPortRange baseAddress="0x9ae8" rangeLength="0x2" fixed="True" />
<extension startStateId="3" contractName="Microsoft.Singularity-
.Extending.ExtensionContract" endpointEnd="Exp"
assembly="Namespace.Contracts" />
<serviceProvider startStateId="3" contractName="Microsoft-
.Singularity.Io.VideoDeviceContract" endpointEnd="Exp"
assembly="Io.Contracts" />
</driverCategory>
...
</manifest>
如章节2.2所描述的那样,应用程序是Singularity中的第一个抽象类。Singularity安装程序必须往应用程序中添加一段代码以运行应用程序。
安装程序以应用程序中的元数据开始。安装程序验证以确保每个应用程序的程序集存在并且是类型和内存安全的。它也要验证以确保所有的通讯信道被正确的实现以及所有的程序集依赖性和Kernel ABI上的依赖性能正确地解决。
一 旦这些内在特性被解决并验证。下一步安装程序试图解决和验证所有的外部依赖性。例如,安装程序要确保设备驱动程序需要使用的任何硬件资源不会和其它任何设 备需要的硬件资源相冲突。安装程序也需要验证以确保应用程序使用的每个信道都存在。如果应用程序输出信道,安装程序要验证以确保这个信道不会和其它应用程 序相冲突。当冲突发生时,系统清单中的策略会解决它们。例如,系统清单也许会声明仅有一个设备驱动程序可以提供视频控制台契约。额外的视频设备的安装会被 禁止,或者仅有一个视频设备在导入的时候被激活。
如章节4.9所描述的那样,使用编译时反射(CTR)产生受信任的代码,以便为涉及到的系统资源初始化进程中的对象。在安装的时候,CTR模板使用属性化的程序元素执行,这些程序元素存在于由应用程序清单所命名的程序集中。
在更新系统清单元数据以合并新的应用程序或设备驱动程序之后,安装进程完成。
在目前的实现中,整个安装进程离线发生,一个安装仅在下一次系统导入的时候可见。虽然这个纯粹的离线安装也许不易扩展为支持在线安装,但是在线安装在我们的使用场景中还没被需要。
5.2.3
运行时
在运行时,元数据驱动Kernel、设备驱动程序、服务和应用程序的安装。引导载入器读取系统清单的一部分以决定应该载入哪个Kernel,设备驱动程序和服务。载入和开始执行的顺序没有在任何地方指定,系统推断从特定的依赖性上推断载入和执行的顺序。
当每个应用程序开始时,Kernel验证和解决所有的元数据依赖性并在Kernel中构造一个进程配置记录。利用CTR嵌入应用程序中的受信任代码解析这个配置记录,为访问外部资源实例化本地对象,并将本地对象植入进程对象空间中的一个配置对象中。
返回到S3Trio64设备驱动程序这个例子中,驱动程序配置纪录中的Kernel记录frameBuffer,textBuffer和fontBuffer对IoMemoryRange对象的需要。Kernel也记录为了控制,高级的和gpstat的输入/输入端口的IoPortRange对象。Kernel创建一个信道用来连接设备驱动程序和输入/输出子系统,创建第二个信道用来连接驱动程序和命名空间。信道端点被添加到驱动程序的配置记录中。
当设备驱动程序开始执行时,在它的运行时中,受信任代码在驱动程序的对象空间中创建合适的IoMemeoryRange和IoPortRange对象。因为这些对象的构造函数只能在受信任的运行时代码中访问,所以一个设备驱动程序只能访问那些已在它的元数据中声明的和经kernel输入/输出子系统检查过冲突的输入输出资源。
在应用程序的元数据中声明信道端点可以确保三个重要的特性。第一,通过静态验证,确保Singularity进程中的代码只能以严格依照信道契约的方式,在完全声明的信道下通信。第二,应用程序不包含全局名称。例如,S3Trio64视频设备不知道系统命名空间下的/dev/video名称。取而代之,驱动程序使用局部名称S3Trio64Config.video指向一个带有指定契约(ServiceProviderContract)的信道。整个I/O命名空间的布局能在不影响一行视频驱动程序代码的情况下改变。第三,依照可能最小特权的原则,应用程序能sandboxed,以移除错误源和安全弱点。例如,尽管S3Trio64驱动程序占据一个连接着系统命名空间的端点,这个驱动程序不能创建新的名称或连接别的系统进程。
5.2.4
映射对应名称空间
为了使访问元数据变得简单,元数据与系统名称空间做了映射。例如,I/O系统创建了一个名称空间数描述当前硬件和设备驱动程序的对应。/hardware/locations列出了所有的buses和每个bus的位置。一个位置代表一个目录树,包含了位于这个位置的驱动程序实例的一个动态连接。
简单的说,/hardware/registrations树列出了每个注册在系统上的驱动程序。在这棵树里有一个动态连接,这个连接指向为相应的硬件信号前缀注册的驱动程序。
/hardware/devices树包含一个入口,该入口针对系统中的每个物理设备实例。一个设备的信号(由设备的枚举所决定)在目录结构中反映。在这棵树中,每个设备的实例是一棵独立的子树,带有指向位置和设备树中的相应实体的动态连接,以展示设备实体是怎么被发现,联合和激活。
/hardware/drivers树 列出了每个注册过的驱动程序,带有一棵针对每个设备实例化的子树。这儿的名称是基于名称空间中该驱动程序类的名称本身。对于特殊的设备,这棵树由指向这个 驱动程序的可执行镜像的动态连接所组成。它也包含了针对于每个驱动程序实体的子树。这棵子树持有相应设备实体的连接。同时被包含在这个空间的还有对所有ServiceProviderContract端点的绑定,这些端点有每个驱动程序的实体所创建。
最后,/dev名称空间是一个公共的目录,持有指向/hardware/drivers子树中ServiceProviderContract端点的动态连接。在这种方式下,一个应用程序一定需要一个公共的名称,并不需要知道驱动程序的真正名称。
5.3
名称服务器
对所有的系统中的服务,Singularity提 供了一个单独的,唯一的名称空间。这个名称空间包含了短暂的系统服务,例如象设备驱动程序,网络连接和文件系统中的持久化存储。这个名称空间由一个著名的 名称服务器和服务所实现。这个名称服务器允许服务在一个分级的名称空间中注册和注销它们本省,所以它们能够被客户端所发现。服务对请求作出回应,并且通过 实现名称服务器的契约,能够在它的配置点之外扩展它的名称空间。
名称空间是分级的。客户端程序能同过路径名称访问服务和刷新名称服务器上的信道。简单的路径名称包括:”/filessystems/ntfs”或者”/tcp/128.0.0.1/80。概念上,名称空间由目录和服务所组成。目录是共享普通路径前缀的目录和服务的集合。服务是动态实体,回应已在其之上注册的信道的请求。
完整的名称空间也许并不存在于一个单独的名称服务器上。一个服务(包括在根名称服务器上同样的)也许注册去处理在分级中的某个点之下所有的请求。注册,注销和寻找对这棵子树的消息比名称服务器帮手先进。这个功能与Unix文件系统下的装配点类似。然而,这个附加的名称服务器不需要向跟服务器那样操作。例如,一个TCP服务能导入巨大的动态ip地址空间,根据需要创建连接,助手名称服务器能实现动态连接。