C Sharp Bare Bones: Difference between revisions
[unchecked revision] | [unchecked revision] |
(Created page with "{{Rating|2}} This tutorial is intended to help you write a simple 'Hello World' OS in C# which you can then compile to machine code for the x86_64 architecture and boot via [...") |
m (Added c# page link) |
||
Line 1: | Line 1: | ||
{{Rating|2}} |
{{Rating|2}} |
||
This tutorial is intended to help you write a simple 'Hello World' OS in C# which you can then compile to machine code for the x86_64 architecture and boot via [[GRUB]]. There are a number of tools for compiling C# to [[CIL]], including Microsoft's csc (distributed with [http://www.microsoft.com/net Microsoft.NET]) and mcs/gmcs/dmcs (distributed with [http://www.mono-project.com Mono]). In addition there are a number of tools for compiling [[CIL]] to native machine code in an ahead-of-time manner, including Microsoft's ngen, mono (with the --aot option), [http://cosmos.codeplex.com/ Cosmos'] IL2CPU, mosacl from the [http://www.mosa-project.org/projects/mosa MOSA project] and tysila from the [http://www.tysos.org/redmine/projects/tysos/ tysos] project. Given the author's familiarity with tysos, that is what we will focus on here. |
This tutorial is intended to help you write a simple 'Hello World' OS in [[C Sharp | C#]] which you can then compile to machine code for the x86_64 architecture and boot via [[GRUB]]. There are a number of tools for compiling C# to [[CIL]], including Microsoft's csc (distributed with [http://www.microsoft.com/net Microsoft.NET]) and mcs/gmcs/dmcs (distributed with [http://www.mono-project.com Mono]). In addition there are a number of tools for compiling [[CIL]] to native machine code in an ahead-of-time manner, including Microsoft's ngen, mono (with the --aot option), [http://cosmos.codeplex.com/ Cosmos'] IL2CPU, mosacl from the [http://www.mosa-project.org/projects/mosa MOSA project] and tysila from the [http://www.tysos.org/redmine/projects/tysos/ tysos] project. Given the author's familiarity with tysos, that is what we will focus on here. |
||
==Prerequisites== |
==Prerequisites== |
Revision as of 17:55, 15 June 2012
Difficulty level |
---|
![]() Medium |
This tutorial is intended to help you write a simple 'Hello World' OS in C# which you can then compile to machine code for the x86_64 architecture and boot via GRUB. There are a number of tools for compiling C# to CIL, including Microsoft's csc (distributed with Microsoft.NET) and mcs/gmcs/dmcs (distributed with Mono). In addition there are a number of tools for compiling CIL to native machine code in an ahead-of-time manner, including Microsoft's ngen, mono (with the --aot option), Cosmos' IL2CPU, mosacl from the MOSA project and tysila from the tysos project. Given the author's familiarity with tysos, that is what we will focus on here.
Prerequisites
You will need a binutils which can target the x86_64-elf target, mono (for the gmcs compiler) or csc from .net, grub and its xorriso dependency (for generating iso images), NASM/YASM/something similar for the assembly stub and of course tysos. For debian-based systems try sudo apt-get install nasm xorriso qemu mono-devel.
For tysos, use subversion to get the latest sources: svn co http://www.tysos.org/svn/trunk tysos, or download the latest tar ball from http://www.tysos.org/files/src/tysos-latest.tar.bz2.
Building tysila
Tysos is a project developing a full OS kernel and drivers in C#, however we only want the compiler from it therefore we only want to compile part of the build tree. Enter the tysos directory and run
cd tybuild && make && cd .. cd mono/corlib && make mscorlib.dll && cd ../.. cd tysila2 && make && cd ..
You may need to enable binfmt_misc support for mono (if trying this on linux). How to do this is outside the scope of this document but the answer is easily obtained via Google.
Directory layout
We will create a directory to build our OS and ISO file in. Something like mkdir -p barebones/iso/boot/grub should suffice. Enter the barebones directory and start creating some files.
loader.asm
This is the assembly stub which will contain a Multiboot header and stub code for switching to long mode.
global loader
global sthrow
extern kmain
MODULEALIGN equ 1<<0
MEMINFO equ 1<<1
FLAGS equ MODULEALIGN | MEMINFO
MAGIC equ 0x1BADB002
CHECKSUM equ -(MAGIC + FLAGS)
IA32_EFER equ 0xC0000080
LME equ 0x100
STACKSIZE equ 0x1000
section .text
align 4
dd MAGIC
dd FLAGS
dd CHECKSUM
[BITS 32]
loader:
mov esp, stack + STACKSIZE
; set PAE in CR4
mov eax, cr4
or eax, 0x20
mov cr4, eax
; clear paging tables
lea edi, [pml4t]
mov ecx, 1024
rep stosd
lea edi, [pdpt]
mov ecx, 1024
rep stosd
lea edi, [pd]
mov ecx, 1024
rep stosd
; identity map first 2 MiB
lea edi, [pml4t]
lea eax, [pdpt]
or eax, 3
mov [edi], eax
lea edi, [pdpt]
lea eax, [pd]
or eax, 3
mov [edi], eax
mov dword [pd], 0x83
; set up cr3 with the pml4t
lea eax, [pml4t]
mov cr3, eax
; enable long mode
mov ecx, IA32_EFER
rdmsr
or eax, LME
wrmsr
; enable paging and write-back cacheing
mov eax, cr0
or eax, 0x80000000
and eax, 0x9fffffff
mov cr0, eax
; load a 64 bit gdt
lgdt [gdt64info]
jmp 0x8:.owngdt
.owngdt:
[BITS 64]
call kmain
cli
.halt:
hlt
jmp .halt
sthrow:
hlt:
jmp sthrow
section .data
align 32
gdt64info:
dw gdt64_end - gdt64 - 1
dd gdt64
align 32
gdt64 dd 0, 0 ; null descriptor
code db 0xff, 0xff, 0x00, 0x00, 0x00, 10011010b, 10101111b, 0x00
data db 0xff, 0xff, 0x00, 0x00, 0x00, 10010010b, 11001111b, 0x00
gdt64_end:
section .bss
stack: resb STACKSIZE
pml4t: resb 0x1000
pdpt: resb 0x1000
pd: resb 0x1000
kernel.cs
This is the actual simple kernel - it just prints a message to the screen.
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
The linker script
ENTRY (loader)
SECTIONS
{
. = 0x00100000;
.text ALIGN(0x1000) :
{
*(.text)
}
.rodata ALIGN(0x1000) :
{
*(.rodata*)
}
.data ALIGN(0x1000) :
{
*(.data)
}
.bss ALIGN(0x1000) :
{
*(COMMON)
*(.bss)
}
}
iso/boot/grub/grub.cfg
This is a short file to tell grub where to find our kernel
multiboot /kernel.bin boot
Building it all
The following commands should build your new C# kernel. First, assemble the multiboot stub:
nasm -felf64 -o loader loader.asm
To compile the .cs file to a .exe you have a choice of three options (depending on your architecture):
gmcs /target:exe /out:kernel.exe /unsafe kernel.cs csc /target:exe /out:kernel.exe /unsafe kernel.cs /path/to/tysos/tybuild/bin/Release/tybuild.exe /unsafe kernel.cs
To compile kernel.exe to machine code we use tysila:
/path/to/tysos/tysila2/bin/Release/tysila2.exe -fno-rtti --rename-epoint kmain -L/path/to/tysos/mono/corlib -o kernel.o kernel.exe
Here, the -fno-rtti switch disables run-time type information, support for which would greatly enlarge the size of your kernel and require you to provide a great number of run time functions to support this. The --rename-epoint switch renames the entry point to anything we like.
To link:
x86_64-elf-ld -T linker.ld -z max-page-size=0x1000 -o iso/kernel.bin loader.o kernel.o
Then we make a bootable iso image with:
grub-mkrescue -o barebones.iso iso
And run it on qemu with:
qemu-system-x86_64 -cdrom barebones.iso