C Sharp Bare Bones: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(Cleaned up assembly stub (mostly by using 32 bit mode instead of 64 bit, thus avoiding paging setup/mode switching etc))
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(11 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{BeginnersWarning}}
{{Rating|2}}
{{Rating|2}}


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 IA32 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 IA32 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://gocosmos.org 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==
Line 7: Line 8:
You will need a binutils which can target the elf_i386 emulation, 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 tysila. For debian-based systems try sudo apt-get install nasm xorriso qemu mono-devel.
You will need a binutils which can target the elf_i386 emulation, 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 tysila. For debian-based systems try sudo apt-get install nasm xorriso qemu mono-devel.


For tysila, you can download pre-compiled binaries from http://www.tysos.org/files/tysila/tysila-latest.tar.bz2 and extract them to somewhere in your path. Please note these binaries will not work on 64-bit Windows due to a bug in the current Microsoft CLR (see [http://connect.microsoft.com/VisualStudio/feedback/details/635365/runtimehelpers-initializearray-fails-on-64b-framework here]) so instead you must build it from source.
For tysila, you can download pre-compiled binaries from 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) and extract them to somewhere in your path. Please note these binaries will not work on 64-bit Windows due to a bug in the current Microsoft CLR (see [http://connect.microsoft.com/VisualStudio/feedback/details/635365/runtimehelpers-initializearray-fails-on-64b-framework here]) so instead you must build it from source.


==Building tysila==
==Building tysila==


This is only required if you have not downloaded the pre-compiled binaries above. 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. 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
This is only required if you have not downloaded the pre-compiled binaries above. Use subversion to get the latest sources 'svn co http://www.tysos.org/svn/trunk tysos' (not in Wayback Machine), or download the latest tar ball from http://www.tysos.org/files/src/tysos-latest.tar.bz2 (http://web.archive.org/web/*/http://www.tysos.org/files/src/tysos-latest.tar.bz2). 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
<syntaxhighlight lang="bash">
<pre>
cd tybuild && make && cd ..
cd tybuild && make && cd ..
cd mono/corlib && make mscorlib.dll && cd ../..
cd mono/corlib && make mscorlib.dll && cd ../..
cd tysila2 && make && cd ..
cd tysila2 && make && cd ..
</syntaxhighlight>
</pre>


You will need to put the 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 and tybuild/bin/Release/tybuild.exe files somewhere in your path.
You will need to put the 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 and tybuild/bin/Release/tybuild.exe files somewhere in your path.
Line 28: Line 29:
===loader.asm===
===loader.asm===


This is the assembly stub which will contain a Multiboot header and stub code for switching to long mode.
This is the assembly stub which will contain a Multiboot header.


<source lang="asm">
<syntaxhighlight lang="asm">
global sthrow
global sthrow


Line 47: Line 48:
dd FLAGS
dd FLAGS
dd CHECKSUM
dd CHECKSUM

</source>
sthrow:
hlt
jmp sthrow
</syntaxhighlight>


===kernel.cs===
===kernel.cs===
Line 53: Line 58:
This is the actual simple kernel - it just prints a message to the screen.
This is the actual simple kernel - it just prints a message to the screen.


<source lang="csharp">
<syntaxhighlight lang="csharp">
namespace BareBones
namespace BareBones
{
{
Line 84: Line 89:
}
}
}
}
</syntaxhighlight>
</source>


===linker.ld===
===linker.ld===
Line 90: Line 95:
The linker script
The linker script


<source lang="text">
<syntaxhighlight lang="c">
ENTRY (_start)
ENTRY (_start)


Line 118: Line 123:
}
}
}
}
</syntaxhighlight>
</source>


===iso/boot/grub/grub.cfg===
===iso/boot/grub/grub.cfg===
This is a short file to tell grub where to find our kernel
This is a short file to tell grub where to find our kernel
<syntaxhighlight lang="c">
<pre>
multiboot /kernel.bin
multiboot /kernel.bin
boot
boot
</syntaxhighlight>
</pre>


==Building it all==
==Building it all==
The following commands should build your new C# kernel. First, assemble the multiboot stub:
The following commands should build your new C# kernel. First, assemble the multiboot stub:
<pre>nasm -felf -o loader loader.asm</pre>
<syntaxhighlight lang="bash">nasm -felf -o loader.o loader.asm</syntaxhighlight>
To compile the .cs file to a .exe you have a choice of three options (depending on your architecture):
To compile the .cs file to a .exe you have a choice of three options (depending on your architecture):
<syntaxhighlight lang="bash">
<pre>
gmcs /target:exe /out:kernel.exe /unsafe kernel.cs
gmcs /target:exe /out:kernel.exe /unsafe kernel.cs
csc /target:exe /out:kernel.exe /unsafe kernel.cs
csc /target:exe /out:kernel.exe /unsafe kernel.cs
tybuild.exe /unsafe kernel.cs
tybuild.exe /unsafe kernel.cs
</syntaxhighlight>
</pre>
To compile kernel.exe to machine code we use tysila:
To compile kernel.exe to machine code we use tysila:
<pre>tysila2.exe --arch i586-elf-tysos -fno-rtti -o kernel.o kernel.exe</pre>
<syntaxhighlight lang="bash">tysila2.exe --arch i586-elf-tysos -fno-rtti -o kernel.o kernel.exe</syntaxhighlight>
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.
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.


To link:
To link:
<pre>ld -m elf_i386 -T linker.ld -o iso/kernel.bin loader.o kernel.o</pre>
<syntaxhighlight lang="bash">ld -m elf_i386 -T linker.ld -o iso/kernel.bin loader.o kernel.o</syntaxhighlight>


Then we make a bootable iso image with:
Then we make a bootable iso image with:
<pre>grub-mkrescue -o barebones.iso iso</pre>
<syntaxhighlight lang="bash">grub-mkrescue -o barebones.iso iso</syntaxhighlight>


And run it on qemu with:
And run it on qemu with:
<pre>qemu-system-i386 -cdrom barebones.iso</pre>
<syntaxhighlight lang="bash">qemu-system-i386 -cdrom barebones.iso</syntaxhighlight>


[[Category:Bare bones tutorials]]
[[Category:Bare bones tutorials]]
[[Category:CSharp]]

Latest revision as of 05:20, 9 June 2024

WAIT! Have you read Getting Started, Beginner Mistakes, and some of the related OS theory?
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 IA32 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 elf_i386 emulation, 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 tysila. For debian-based systems try sudo apt-get install nasm xorriso qemu mono-devel.

For tysila, you can download pre-compiled binaries from 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) and extract them to somewhere in your path. Please note these binaries will not work on 64-bit Windows due to a bug in the current Microsoft CLR (see here) so instead you must build it from source.

Building tysila

This is only required if you have not downloaded the pre-compiled binaries above. Use subversion to get the latest sources 'svn co http://www.tysos.org/svn/trunk tysos' (not in Wayback Machine), or download the latest tar ball from http://www.tysos.org/files/src/tysos-latest.tar.bz2 (http://web.archive.org/web/*/http://www.tysos.org/files/src/tysos-latest.tar.bz2). 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 will need to put the 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 and tybuild/bin/Release/tybuild.exe files somewhere in your path.

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.

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

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 (_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

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 -felf -o loader.o 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
tybuild.exe /unsafe kernel.cs

To compile kernel.exe to machine code we use tysila:

tysila2.exe --arch i586-elf-tysos -fno-rtti -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.

To link:

ld -m elf_i386 -T linker.ld -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-i386 -cdrom barebones.iso