D Bare Bones: Difference between revisions
[unchecked revision] | [unchecked revision] |
(New page: {{Rating|1}}{{Template:Kernel Designs}} ''In this Tutorial we will write a kernel in the D language and boot it.'' <big><b>WAIT! Have you read Getting Started and [[Beginner Mistakes...) |
m (Bot: Replace deprecated source tag with syntaxhighlight) |
||
(36 intermediate revisions by 15 users not shown) | |||
Line 1: | Line 1: | ||
{{Disputed|Talk:D Bare Bones}} |
|||
{{Rating|1}}{{Template:Kernel Designs}} |
|||
{{TutorialExplain}} |
|||
{{BeginnersWarning}} |
|||
{{Rating|1}}{{Template:Kernel designs}} |
|||
In this Tutorial we will write a kernel in the [[D]] language and boot it. |
|||
<big><b>WAIT! Have you read [[Getting Started]] and [[Beginner Mistakes]]?</b></big> |
|||
==Preface== |
==Preface== |
||
Line 9: | Line 10: | ||
The following tutorial assumes basic knowledge of a compiler, linker and assembler toolchain. |
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. |
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== |
|||
<syntaxhighlight lang="asm"> |
|||
global start |
|||
extern kmain ; Allow kmain() 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 kmain |
|||
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 |
|||
</syntaxhighlight> |
|||
Assemble that with: |
|||
<syntaxhighlight lang="bash">nasm -f elf -o start.o start.asm</syntaxhighlight> |
|||
==kernel.main.d== |
|||
<syntaxhighlight lang="d"> |
|||
module kernel.main; |
|||
import core.volatile; |
|||
extern(C) void kmain(uint magic, uint addr) { |
|||
ubyte* vidmem = cast(ubyte*)0xFFFF_8000_000B_8000; //Video memory address |
|||
for (int i = 0; i < 80*25*2; i++) { //Loops through the screen and clears it |
|||
volatileStore(vidmem + i, 0); |
|||
} |
|||
volatileStore(vidmem, 'D' & 0xFF); //Prints the letter D |
|||
volatileStore(vidmem + 1, 0x07); //Sets the colour for D to be light grey (0x07) |
|||
for (;;) { //Loop forever. You can add your kernel logic here |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
You then compile that with: |
|||
<syntaxhighlight lang="bash">gdc -fno-druntime -m32 -c kernel.main.d -o kernel.main.o -g</syntaxhighlight> |
|||
==linker.ld== |
|||
<syntaxhighlight lang="c"> |
|||
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 = .; |
|||
} |
|||
</syntaxhighlight> |
|||
Now finally you can link all of that with: |
|||
<syntaxhighlight lang="bash">ld -melf_i386 -T linker.ld -o kernel.bin start.o kernel.main.o</syntaxhighlight> |
|||
Your kernel is now kernel.bin, and can now be booted by grub, or run in qemu: |
|||
<syntaxhighlight lang="bash">qemu-system-i386 -kernel kernel.bin</syntaxhighlight> |
|||
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_Bare_Bones_II|Creating a minimal output to the console]] |
|||
[[D_barebone_with_ldc2|D BareBone with 64 bit and ldc2]] |
|||
[[Category:Bare bones tutorials|D bare bones]] |
|||
[[Category:D]] |
Latest revision as of 05:20, 9 June 2024
Difficulty level |
---|
![]() Beginner |
Kernel Designs |
---|
Models |
Other Concepts |
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 kmain ; Allow kmain() 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 kmain
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.volatile;
extern(C) void kmain(uint magic, uint addr) {
ubyte* vidmem = cast(ubyte*)0xFFFF_8000_000B_8000; //Video memory address
for (int i = 0; i < 80*25*2; i++) { //Loops through the screen and clears it
volatileStore(vidmem + i, 0);
}
volatileStore(vidmem, 'D' & 0xFF); //Prints the letter D
volatileStore(vidmem + 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.