C Sharp Bare Bones
难度等级 |
---|
中等 |
本教程旨在帮助你在 C# 中编写一个简单的 'Hello World' 操作系统,然后你可以编译为IA32体系结构的机器码并通过GRUB启动。 有许多用于将C# 编译到 CIL 的工具,包括微软的csc (与 Microsoft.NET 一起分发) 和mcs/gmcs/dmcs (与 [mono-project.com Mono] 一起分发)。 此外,还有许多以提前编译方式将 CIL 编译到本机机器码的工具,包括Microsoft的ngen,mono (带有-aot选项),Cosmos的 IL2CPU,来自 [http:// mosa-project.org/projects/mosa MOSA项目]的mosacl 和来自 tysos 项目的tysila。 鉴于作者对tysos的较为程度,我们在这里重点介绍tysos。
先决条件
你将需要一个binutils,它可以从.net,grub及其xorriso依赖 (用于生成iso图像),NASM/YASM/类似的汇编Stub,当然还有tysila,以上这些工具逐步完成针对elf_i386仿真,mono (对于gmcs编译器) 或csc的目标构建。 对于基于debian的系统,请尝试运行sudo apt-get install nasm xorriso qemu mono-devel。
对于tysila,你可以从以下位置下载预编译的二进制文件 http://www.tysos.org/files/tysila/tysila-latest.tar.bz2 (http://web.archive.org/web/20170317154703/http://www.tysos.org/files/tysila/tysila-latest.tar.bz2) 然后在路径下解压它们。 请注意,由于当前Microsoft CLR中的错误,这些二进制文件在64位Windows上不起作用 (请参阅 此处),因此你必须从源代码构建它。
构建tysila
仅当你尚未下载上述预编译的二进制文件时,才需要这样做。 使用subversion获取最新的源代码 “svn co http://www.tysos.org/svn/trunk tysos” (不在Wayback Machine中),或从http://www.tysos.org/files/src/tysos-latest.tar.bz2下载最新的tar包(http://web.archive.org/web/*/http://www.tysos.org/files/src/tysos-latest.tar.bz2)。 Tysos是一个在C# 中开发完整的OS内核和驱动程序的项目,但是我们只想要编译器,因此我们只想编译构建树的一部分。 进入tysos目录并运行
cd tybuild && make && cd ..
cd mono/corlib && make mscorlib.dll && cd ../..
cd tysila2 && make && cd ..
你需要将mono/corlib/mscorlib.dll、tysila2/bin/Release/tysila2.exe、tysila2/bin/Release/libsupcs.dll、tysila2/bin/Release/libtysila.dll、tysila2/bin/Release/tydbfile.dll、tysila2/bin/Release/tydisasm.dll和tybuild/bin/Release/tybuild.exe文件放在路径中的某个地方。
你可能需要为mono启用binfmt_misc支持 (如果在linux上尝试此功能)。 如何做到这一点不在本文档的范围内,但答案很容易通过Google获得。
目录布局
我们将创建一个目录来构建我们的操作系统和ISO文件。 像mkdir -p barebones/iso/boot/grub这样应该足够了。 进入barebones目录,开始创建一些文件。
loader.asm
这是汇编Stub,它要包含一个多引导头。
global sthrow
extern kmain
MODULEALIGN equ 1<<0
MEMINFO equ 1<<1
FLAGS equ MODULEALIGN | MEMINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC + FLAGS)
section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
sthrow:
hlt
jmp sthrow
kernel.cs
这是实际的简单内核-它只是将消息打印到屏幕上。
namespace BareBones
{
class Program
{
static int pos = 0;
unsafe static void Main()
{
// Clear the screen
for(int i = 0; i < 80 * 25 * 2; i++)
*(byte *)(0xb8000 + i) = 0;
// Say hi
Print("Hello World!");
}
static void Print(string s)
{
foreach(char c in s)
Print(c);
}
unsafe static void Print(char c)
{
*(byte *)(0xb8000 + pos) = (byte)c;
*(byte *)(0xb8000 + pos + 1) = 0x0f;
pos += 2;
}
}
}
linker.ld
链接器脚本
ENTRY (_start)
SECTIONS
{
. = 0x00100000;
.text ALIGN(0x1000) :
{
*(.text)
}
.rodata ALIGN(0x1000) :
{
*(.rodata*)
}
.data ALIGN(0x1000) :
{
*(.data)
}
.bss ALIGN(0x1000) :
{
*(COMMON)
*(.bss)
}
}
iso/boot/grub/grub.cfg
这是一个简短的文件,告诉grub在哪里可以找到我们的内核
multiboot /kernel.bin
boot
把它全部构建起来
以下命令应该构建你的新C#内核。首先,组装multiboot stub:
nasm -felf -o loader.o loader.asm
为了编译.cs文件到a.exe你可以选择三个选项 (取决于你的体系结构):
gmcs /target:exe /out:kernel.exe /unsafe kernel.cs
csc /target:exe /out:kernel.exe /unsafe kernel.cs
tybuild.exe /unsafe kernel.cs
要编译kernel.exe到机器码,我们使用tysila:
tysila2.exe --arch i586-elf-tysos -fno-rtti -o kernel.o kernel.exe
在这里,-fno-rtti切换禁用运行时类型信息,如果对其支持将大大扩大内核的大小,并要求你提供大量的运行时功能来支持这一点。
开始链接:
ld -m elf_i386 -T linker.ld -o iso/kernel.bin loader.o kernel.o
然后我们建立一个可启动ISO映像:
grub-mkrescue -o barebones.iso iso
并在qemu上运行它:
qemu-system-i386 -cdrom barebones.iso