From OSDev Wiki

The factual accuracy of this article or section is disputed.

Please see the relevant discussion on the talk page.

This tutorial needs to explain what the code does as tutorials are not just copy paste. You can help out by editing this page to include more context to what the code does.

WAIT! Have you read Getting Started, Beginner Mistakes, and some of the related OS theory?

Difficulty level

Beginner

In this Tutorial we will write a kernel in the D language and boot it.

Preface

The following tutorial assumes basic knowledge of a compiler, linker and assembler toolchain. It also of course assumes prior knowledge of the D programming language.

Overview

In this tutorial we will create a simple D kernel that prints 'D' on to the screen. The basic setup will consist of three files:

start.asm

kernel.main.d

linker.ld

start.asm

global start extern main ; Allow main() to be called from the assembly code extern start_ctors , end_ctors , start_dtors , end_dtors MODULEALIGN equ 1 << 0 MEMINFO equ 1 << 1 FLAGS equ MODULEALIGN | MEMINFO MAGIC equ 0x1BADB002 CHECKSUM equ - ( MAGIC + FLAGS ) section . text ; Next is the Grub Multiboot Header align 4 MultiBootHeader : dd MAGIC dd FLAGS dd CHECKSUM STACKSIZE equ 0x4000 ; 16 KiB if you're wondering static_ctors_loop : mov ebx , start_ctors jmp . test . body : call [ ebx ] add ebx , 4 . test : cmp ebx , end_ctors jb . body start : mov esp , STACKSIZE + stack push eax push ebx call main static_dtors_loop : mov ebx , start_dtors jmp . test . body : call [ ebx ] add ebx , 4 . test : cmp ebx , end_dtors jb . body cpuhalt : hlt jmp cpuhalt section . bss align 32 stack : resb STACKSIZE

Assemble that with:

nasm -f elf -o start.o start.asm

kernel.main.d

module kernel. main ; import core. bitop ; // will be core.volatile in later gdc extern ( C ) void main ( uint magic , uint addr ) { int ypos = 0 ; //Starting points of the cursor int xpos = 0 ; const uint COLUMNS = 80 ; //Screensize const uint LINES = 25 ; ubyte * vidmem = cast ( ubyte * ) 0xFFFF _8000_000B_8000 ; //Video memory address for ( int i = 0 ; i < COLUMNS * LINES * 2 ; i ++ ) { //Loops through the screen and clears it volatileStore ( vidmem + i , 0 ) ; } volatileStore ( vidmem + ( xpos + ypos * COLUMNS ) * 2 , 'D' & 0xFF ) ; //Prints the letter D volatileStore ( vidmem + ( xpos + ypos * COLUMNS ) * 2 + 1 , 0x07 ) ; //Sets the colour for D to be light grey (0x07) for ( ;; ) { //Loop forever. You can add your kernel logic here } }

You then compile that with:

gdc -fno-druntime -m32 -c kernel.main.d -o kernel.main.o -g

linker.ld

OUTPUT_FORMAT ( elf32 - i386 ) ENTRY ( start ) SECTIONS { . = 0x00100000 ; . text : { code = . ; _code = . ; __code = . ; * ( . text ) * ( . rodata ) } . rodata ALIGN ( 0x1000 ) : { * ( . rodata ) } . data ALIGN ( 0x1000 ) : { data = . ; _data = . ; __data = . ; * ( . data ) start_ctors = . ; * ( . ctors ) end_ctors = . ; start_dtors = . ; * ( . dtors ) end_dtors = . ; } . bss : { sbss = . ; bss = . ; _bss = . ; __bss = . ; * ( COMMON ) * ( . bss ) ebss = . ; } end = . ; _end = . ; __end = . ; }

Now finally you can link all of that with:

ld -melf_i386 -T linker.ld -o kernel.bin start.o kernel.main.o

Your kernel is now kernel.bin, and can now be booted by grub, or run in qemu:

qemu-system-i386 -kernel kernel.bin

Note the "-fno-druntime" argument above. This is how gdc spells the -betterC flag from other D compilers, and the "Better C" page of the D language reference explains how this limits the language. If you want to drop that you'll have to add the D runtime to your kernel.

Hopefully this has gotten you started on writing your operating system in the D programming language.

Further reading

D BareBone with 64 bit and ldc2