Cosmos操作系统开发工具包详解

Cosmos是一个操作系统开发工具包,它使用Visual Studio作为开发环境。尽管名称中包含C#,但可以使用任何基于.NET的语言,包括VB.NET、Fortran、Delphi Prism、IronPython、F#等。Cosmos本身及其内核例程主要是用C#编写的,因此得名Cosmos。除此之外,NOSMOS(.NET开源托管操作系统)听起来很愚蠢。

Cosmos并不是传统意义上的操作系统,而是一个“操作系统工具包”,或者用话来说就是“操作系统乐高”。Cosmos允许像使用Visual Studio和C#创建应用程序一样创建操作系统。大多数用户可以在几分钟内编写并启动他们自己的操作系统,全部使用Visual Studio。Cosmos支持Visual Studio中的集成项目类型,以及集成调试器、断点、监视点等。可以像调试普通的C#或VB.NET应用程序一样调试操作系统。

介绍

Cosmos可以通过USB、以太网、DVD甚至真正的硬盘在真实硬件上启动,但大多数用户使用VMWare,因为在开发过程中它更快。给定以下源代码:

public class Program { public static void Main() { Console.WriteLine("Hello, Cosmos!"); } }

当按下F5时,代码将被转换成一个完整的操作系统,并在VMWare中启动:

对许多人来说,这可能看起来像魔法。确实有很多代码需要编写才能使这个过程如此无缝。以下是发生的基本步骤。

编译

Visual Studio将C#等.NET语言编译成中间语言(IL),使用名为IL2CPU的Cosmos实用工具。IL通常由Windows上的JIT(即时)编译器在可执行文件运行时处理。Visual Studio生成的可执行文件实际上不是本地代码,而是IL字节码。.NET可执行文件中通常存在的唯一本地代码是一小段引导代码,它允许Windows像运行普通可执行文件一样运行它。这段引导代码调用.NET JIT,然后读取并编译可执行文件中的IL。可以使用许多工具查看IL,如ILDasm或反射器。

以下是一个Cosmos项目的示例IL:

.method family hidebysig virtual instance void Run() cil managed { .maxstack 1 .locals init ( [ 0] int32 i, [ 1] class BreakpointsKernel.Test xTest) L_0000: nop L_0001: ldc.i4.0 L_0002: stloc.0 L_0003: ret }

然后将其传递给一个名为NASM的汇编器,将其转换为二进制格式。

启动

现在有一个二进制文件,但需要启动它。为此,Cosmos使用一个引导程序。所有操作系统都使用引导程序,包括Windows和Linux。计算机的BIOS寻找引导代码,但这个引导代码必须非常小。然后这个引导代码加载一个稍大的引导程序,然后初始化内存并加载更大的操作系统。在转移到操作系统后,引导代码和引导程序从内存中移除。为此,Cosmos使用一个名为Syslinux的引导程序。尽管名字如此,它不是Linux,Cosmos也不是基于Linux构建的。Syslinux的根源涉及旧的Linux引导程序,因此得名。Syslinux只是用来让BIOS启动Cosmos代码,一旦Cosmos代码运行起来,BIOS和Syslinux就不再使用。

调试

Cosmos支持正常的源代码调试,允许跟踪、断点甚至监视。Cosmos还支持实验性的汇编级调试器,以及GDB。为了在Visual Studio中支持调试,Cosmos有一个名为DebugStub的小手写汇编方法。DebugStub在Cosmos执行过程中反复调用,并由Cosmos编译器自动插入。DebugStub使用串行端口与DebugClient通信,DebugClient是Cosmos Visual Studio调试包的一部分。在VMWare上,串行端口映射到管道,DebugClient与管道通信。在物理硬件上调试时,两边都使用串行端口。将来,也将支持通过以太网调试。

硬件

许多框架类库使用icalls或pinvokes。例如,当.NET需要在屏幕上绘制时,它没有代码。它使用pinvoke直接调用Windows API。icalls类似,但映射到.NET运行时的内部函数。因为Cosmos在真实硬件上运行,没有.NET运行时和Windows API,所以必须实现这样的代码。Cosmos使用插件来实现这些。插件是一段代码,它标记一个类和/或方法,它将在IL2CPU阶段替换。插件可以用C#(或任何.NET语言)、汇编或X#编写。插件也可以用来将C#代码与汇编代码接口。Cosmos努力最小化编写汇编代码的需要,但在内核中直接与硬件交互时,必须使用汇编。插件通过创建实际运行汇编的C#类来隐藏这些深层细节,远离开发者。IOPort类就是这样一个例子。

public AtaPio(Core.IOGroup.ATA aIO, Ata.ControllerIdEnum aControllerId, Ata.BusPositionEnum aBusPosition) { IO = aIO; mControllerID = aControllerId; mBusPosition = aBusPosition; // Disable IRQs, we use polling currently IO.Control.Byte = 0x02; mDriveType = DiscoverDrive(); if (mDriveType != SpecLevel.Null) { InitDrive(); } }

这是PATA(硬盘访问)类的一个小程序。它能够使用C#代码直接与CPU IO总线通信。尽管IOPort类(此代码中的IO变量)的部分是用C#编写的,但部分是用X86汇编代码插入的。

Cosmos是用C#编写的。Cosmos开发人员,包括内核开发人员,都使用C#。然而IL2CPU库必须处理汇编,当然中处理编译器代码的人会使用X86。以前有自己的基于类的“内联编译器”。它工作得很好,但总是想要更多。亲切地称解决方案为X#(来自X86)。这个想法是将所有的源代码放在一个地方,并保持类型安全。以前的基于类的内联编译器做到了这一点。典型的代码看起来像这样:

new Move(Registers.DX, (xComAddr + 1).ToString()); new Move(Registers.AL, 0.ToString()); new Out("dx", "al");// disable all interrupts new Move(Registers.DX, (xComAddr + 3).ToString()); new Move(Registers.AL, 0x80.ToString()); new Out("dx", "al");// Enable DLAB (set baud rate divisor) new Move(Registers.DX, (xComAddr + 0).ToString()); new Move(Registers.AL, 0x1.ToString()); new Out("dx", "al");// Set diviso (low byte) new Move(Registers.DX, (xComAddr + 1).ToString()); new Move(Registers.AL, 0x00.ToString()); new Out("dx", "al");// // set divisor (high byte) UInt16 xComStatusAddr = (UInt16)(aComAddr + 5); Label = "WriteByteToComPort"; Label = "WriteByteToComPort_Wait"; DX = xComStatusAddr; AL = Port[DX]; AL.Test(0x20); JumpIfEqual("WriteByteToComPort_Wait"); DX = aComAddr; AL = Memory[ESP + 4]; Port[DX] = AL; Return(4); Label = "DebugWriteEIP"; AL = Memory[EBP + 3]; EAX.Push(); Call(); AL = Memory[EBP + 2]; EAX.Push(); Call(); AL = Memory[EBP + 1]; EAX.Push(); Call(); AL = Memory[EBP]; EAX.Push(); Call(); Return();
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485