Zig Bare Bones: Difference between revisions

m
fix syntax highlighting error
[unchecked revision][unchecked revision]
No edit summary
m (fix syntax highlighting error)
 
(14 intermediate revisions by 4 users not shown)
Line 1:
{{Stub}}
{{TutorialExplain}}
{{Sole Editor}}
In this tutorial, we'll make a simple hello world kernel in Zig.
 
== Prerequisites ==
First off, you'll need:
* The [[Zig]] compiler, at least version 0.712.0
* [[GRUB]] as our bootloader to boot the kernel
 
Line 13 ⟶ 14:
 
=== build.zig ===
<sourcesyntaxhighlight lang="czig">
const std = @import("std");
const Builder = @import("std").build.Builder;
Line 41 ⟶ 42:
};
 
const modeoptimize = b.standardReleaseOptionsstandardOptimizeOption(.{});
 
const kernel = b.addExecutable("kernel.elf", "src/main.zig");{
.name = "kernel.setTarget(target);elf",
.root_source_file = b.path("src/main.zig"),
kernel.setBuildMode(mode);
.target = target,
kernel.setLinkerScriptPath(.{ .path = "src/linker.ld" });
kernel .code_modeloptimize = .kernel;optimize,
.code_model = .kernel,
kernel.install();
});
kernel.setLinkerScriptPathsetLinkerScript(.{ .path = "src/linker.ld" });
b.installArtifact(kernel);
 
const kernel_step = b.step("kernel", "Build the kernel");
Line 90 ⟶ 94:
run_step.dependOn(&run_cmd.step);
}
</syntaxhighlight>
</source>
 
=== src/main.zig ===
<sourcesyntaxhighlight lang="czig">
const console = @import("console.zig");
 
Line 125 ⟶ 129:
console.puts("Hello world!");
}
</syntaxhighlight>
</source>
 
=== src/console.zig ===
<sourcesyntaxhighlight lang="czig">
const fmt = @import("std").fmt;
const memWriter = @import("std").memio.Writer;
 
const VGA_WIDTH = 80;
Line 152 ⟶ 156:
LightMagenta = 13,
LightBrown = 14,
White = 15,
};
 
Line 158 ⟶ 162:
var column: usize = 0;
var color = vgaEntryColor(ConsoleColors.LightGray, ConsoleColors.Black);
var buffer = @intToPtras([*]volatile u16, @ptrFromInt(0xB8000));
 
fn vgaEntryColor(fg: ConsoleColors, bg: ConsoleColors) u8 {
return @enumToInt(fg) | (@enumToInt(bg) << 4);
}
 
fn vgaEntry(uc: u8, new_color: u8) u16 {
var c: u16 = new_color;
 
return uc | (c << 8);
}
Line 178 ⟶ 183:
 
pub fn clear() void {
mem.set@memset(u16, buffer[0..VGA_SIZE], vgaEntry(' ', color));
}
 
pub fn putCharAt(c: u8, new_color: u8, x: usize, y: usize) void {
const index: usize = y * VGA_WIDTH + x;
buffer[index] = vgaEntry(c, new_color);
}
Line 188 ⟶ 193:
pub fn putChar(c: u8) void {
putCharAt(c, color, column, row);
column += 1;
if (column == VGA_WIDTH) {
column = 0;
row += 1;
if (row == VGA_HEIGHT)
row = 0;
Line 196 ⟶ 203:
 
pub fn puts(data: []const u8) void {
for (data) |ic|
putChar(data[i]c);
}
 
pub const writer = Writer(void, error{}, callback){ .context = {} };
 
fn callback(_: void, string: []const u8) error{}!usize {
puts(string);
return string.len;
}
 
pub fn printf(comptime format: []const u8, args: anytype) void {
puts(fmt.bufPrintformat(&bufwriter, format, args) catch unreachable);
var buf: [100]u8 = undefined;
puts(fmt.bufPrint(&buf, format, args) catch unreachable);
}
</syntaxhighlight>
</source>
 
=== src/linker.ld ===
A [[linker script]] is also needed. This file tells the linker to place our code at the base address of 1M. In general user-space programming, code are placed at much higher areas, but that requires [[virtual memory]] to be available, or else only few computers could provide such a large physical memory space.
<source lang="asm">
 
We also asks the linker to place <code>.multiboot</code> section at first, because the Multiboot specification says that the Multiboot header must be at the first 8KiB of the kernel file.
 
<pre>
ENTRY(_start)
Line 213 ⟶ 230:
. = 1M;
*(.multiboot) {
KEEP(*(.multiboot))
}
 
.text : ALIGN(4K) {
*(.multiboot)
*(.text)
}
Line 231 ⟶ 251:
}
}
</sourcepre>
 
=== src/grub.cfg ===
Finally, the last thing you need is a GRUB configuration, which tells the GRUB bootloader how to boot our kernel.
<source lang="c">
 
<code>menuentry</code> adds a menu entry to the screen. When you press ENTER in the GRUB menu, GRUB will run the commands in the menu block.
 
<code>multiboot</code> asks GRUB to load our kernel from <code>/boot/kernel.elf</code>, and GRUB automatically runs <code>boot</code> after the menu block, which will fire the boot.
 
<syntaxhighlight lang="unixconfig">
menuentry "Zig Bare Bones" {
multiboot /boot/kernel.elf
}
</syntaxhighlight>
</source>
 
== Build ==
Now that our kernel code is done, we'll now build our kernel by running the command below:
the command below:
 
<sourcesyntaxhighlight lang="bash">
$ zig build
</syntaxhighlight>
</source>
 
To boot our kernel, simply run this command:
 
<sourcesyntaxhighlight lang="bash">
$ zig build run
</syntaxhighlight>
</source>
 
[[Category: Bare bones tutorials]] [[Category:Zig]]