diff --git a/mykernel/README.md b/mykernel/README.md index 14bec04..286bebf 100644 --- a/mykernel/README.md +++ b/mykernel/README.md @@ -13,4 +13,4 @@ Compilation ----------- In the language's directory, just run `make`. You'll need `gcc`, `g++`, `gnat` (GNU Ada), `fpc` (FreePascal -Compiler), `cargo` + `rust`, and `gccgo` (GNU go-lang compiler, NOT the official go-lang compiler!). +Compiler), `cargo` + `rust`, `gccgo` (GNU go-lang compiler, NOT the official go-lang compiler!), and `zig`. diff --git a/mykernel/zig/Makefile b/mykernel/zig/Makefile new file mode 100644 index 0000000..658d272 --- /dev/null +++ b/mykernel/zig/Makefile @@ -0,0 +1,36 @@ +# +# mykernel/zig/Makefile +# +# Copyright (C) 2022 binarycraft +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# This file is part of the BOOTBOOT Protocol package. +# @brief An example Makefile for sample kernel +# +# + +all: mykernel.x86_64.elf + +# Kernel build +mykernel.x86_64.elf: src/** + zig build -Drelease-fast + cp ./zig-out/bin/mykernel.x86_64.elf mykernel.x86_64.elf diff --git a/mykernel/zig/build.zig b/mykernel/zig/build.zig new file mode 100644 index 0000000..db615e3 --- /dev/null +++ b/mykernel/zig/build.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +pub fn build(b: *std.build.Builder) void { + var target = std.zig.CrossTarget{ + .os_tag = .freestanding, + .cpu_arch = .x86_64, + .abi = .none, + }; + + const mode = b.standardReleaseOptions(); + const kernel = b.addExecutable("mykernel.x86_64.elf", "src/main.zig"); + kernel.setLinkerScriptPath(.{ .path = "src/link.ld" }); + kernel.code_model = .kernel; + kernel.setTarget(target); + kernel.setBuildMode(mode); + kernel.install(); + kernel.strip = true; +} diff --git a/mykernel/zig/src/bootboot.zig b/mykernel/zig/src/bootboot.zig new file mode 100644 index 0000000..f0cb4ae --- /dev/null +++ b/mykernel/zig/src/bootboot.zig @@ -0,0 +1,123 @@ +pub const BOOTBOOT_MAGIC = "BOOT"; + +// default virtual addresses for level 0 and 1 static loaders +pub const BOOTBOOT_MMIO = 0xfffffffff8000000; // memory mapped IO virtual address +pub const BOOTBOOT_FB = 0xfffffffffc000000; // frame buffer virtual address +pub const BOOTBOOT_INFO = 0xffffffffffe00000; // bootboot struct virtual address +pub const BOOTBOOT_ENV = 0xffffffffffe01000; // environment string virtual address +pub const BOOTBOOT_CORE = 0xffffffffffe02000; // core loadable segment start + +// minimum protocol level: +// hardcoded kernel name, static kernel memory addresses +pub const PROTOCOL_MINIMAL = 0; +// static protocol level: +// kernel name parsed from environment, static kernel memory addresses +pub const PROTOCOL_STATIC = 1; +// dynamic protocol level: +// kernel name parsed, kernel memory addresses from ELF or PE symbols +pub const PROTOCOL_DYNAMIC = 2; +// big-endian flag +pub const PROTOCOL_BIGENDIAN = 0x80; + +// loader types, just informational +pub const LOADER_BIOS = 0 << 2; +pub const LOADER_UEFI = 1 << 2; +pub const LOADER_RPI = 2 << 2; +pub const LOADER_COREBOOT = 3 << 2; + +// framebuffer pixel format, only 32 bits supported +pub const FramebufferFormat = enum(u8) { + ARGB = 0, + RGBA = 1, + ABGR = 2, + BGRA = 3, +}; + +// mmap entry, type is stored in least significant tetrad (half byte) of size +// this means size described in 16 byte units (not a problem, most modern +// firmware report memory in pages, 4096 byte units anyway). +pub const MMapEnt = extern struct { + ptr: u64 align(1), + size: u64 align(1), + + const Self = @This(); + + pub inline fn getPtr(self: *Self) u64 { + return self.ptr; + } + + pub inline fn getSizeInBytes(self: *Self) u64 { + return self.size & 0xFFFFFFFFFFFFFFF0; + } + + pub inline fn getSizeIn4KiBPages(self: *Self) u64 { + return self.getSizeInBytes() / 4096; + } + + pub inline fn getType(self: *Self) MMapType { + return @intToEnum(MMapType, @truncate(u4, self.size)); + } + + pub inline fn isFree(self: *Self) bool { + return (self.size & 0xF) == 1; + } +}; + +pub const MMapType = enum(u4) { + /// don't use. Reserved or unknown regions + MMAP_USED = 0, + + /// usable memory + MMAP_FREE = 1, + + /// acpi memory, volatile and non-volatile as well + MMAP_ACPI = 2, + + /// memory mapped IO region + MMAP_MMIO = 3, +}; + +pub const INITRD_MAXSIZE = 16; // Mb + +pub const BOOTBOOT = extern struct { + magic: [4]u8 align(1), + size: u32 align(1), + protocol: u8 align(1), + fb_type: u8 align(1), + numcores: u16 align(1), + bspid: u16 align(1), + timezone: i16 align(1), + datetime: [8]u8 align(1), + initrd_ptr: u64 align(1), + initrd_size: u64 align(1), + fb_ptr: u64 align(1), + fb_size: u32 align(1), + fb_width: u32 align(1), + fb_height: u32 align(1), + fb_scanline: u32 align(1), + + arch: extern union { + x86_64: extern struct { + acpi_ptr: u64, + smbi_ptr: u64, + efi_ptr: u64, + mp_ptr: u64, + unused0: u64, + unused1: u64, + unused2: u64, + unused3: u64, + }, + aarch64: extern struct { + acpi_ptr: u64, + mmio_ptr: u64, + efi_ptr: u64, + unused0: u64, + unused1: u64, + unused2: u64, + unused3: u64, + unused4: u64, + }, + } align(1), + + mmap: MMapEnt align(1), +}; diff --git a/mykernel/zig/src/font.psf b/mykernel/zig/src/font.psf new file mode 100644 index 0000000..3e67693 Binary files /dev/null and b/mykernel/zig/src/font.psf differ diff --git a/mykernel/zig/src/link.ld b/mykernel/zig/src/link.ld new file mode 100644 index 0000000..ccc4c31 --- /dev/null +++ b/mykernel/zig/src/link.ld @@ -0,0 +1,57 @@ +/* + * mykernel/c/link.ld + * + * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * This file is part of the BOOTBOOT Protocol package. + * @brief An example linker script for sample kernel + * + */ + +ENTRY(_start) + +mmio = 0xfffffffff8000000; /* these are configurable for level 2 loaders */ +fb = 0xfffffffffc000000; +bootboot = 0xffffffffffe00000; +environment = 0xffffffffffe01000; +/* initstack = 1024; */ +PHDRS +{ + boot PT_LOAD; /* one single loadable segment */ +} +SECTIONS +{ + . = 0xffffffffffe02000; + .text : { + KEEP(*(.text.boot)) *(.text .text.*) /* code */ + *(.rodata .rodata.*) /* data */ + *(.data .data.*) + } :boot + .bss (NOLOAD) : { /* bss */ + . = ALIGN(16); + *(.bss .bss.*) + *(COMMON) + } :boot + + /DISCARD/ : { *(.eh_frame) *(.comment) } +} diff --git a/mykernel/zig/src/main.zig b/mykernel/zig/src/main.zig new file mode 100644 index 0000000..8186413 --- /dev/null +++ b/mykernel/zig/src/main.zig @@ -0,0 +1,149 @@ +/// mykernel/zig/src/main.zig +/// +/// Copyright (C) 2022 binarycraft +/// +/// Permission is hereby granted, free of charge, to any person +/// obtaining a copy of this software and associated documentation +/// files (the "Software"), to deal in the Software without +/// restriction, including without limitation the rights to use, copy, +/// modify, merge, publish, distribute, sublicense, and/or sell copies +/// of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be +/// included in all copies or substantial portions of the Software. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +/// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +/// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +/// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +/// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +/// DEALINGS IN THE SOFTWARE. +/// +/// This file is part of the BOOTBOOT Protocol package. +/// @brief A sample BOOTBOOT compatible kernel +const std = @import("std"); +const BOOTBOOT = @import("bootboot.zig").BOOTBOOT; + +const fontEmbedded = @embedFile("font.psf"); + +// imported virtual addresses, see linker script +extern var bootboot: BOOTBOOT; // see bootboot.zig +extern var environment: [4096]u8; // configuration, UTF-8 text key=value pairs +extern var fb: u8; // linear framebuffer mapped + +// Display text on screen +const PsfFont = packed struct { + magic: u32, // magic bytes to identify PSF + version: u32, // zero + headersize: u32, // offset of bitmaps in file, 32 + flags: u32, // 0 if there's no unicode table + numglyph: u32, // number of glyphs + bytesperglyph: u32, // size of each glyph + height: u32, // height in pixels + width: u32, // width in pixels +}; + +// function to display a string +pub fn puts(string: []const u8) void { + const font = @bitCast(PsfFont, fontEmbedded[0..@sizeOf(PsfFont)].*); + var bytesperline = (font.width + 7) / 8; + var framebuffer = @intToPtr([*]u32, @ptrToInt(&fb)); + for (string) |char, i| { + var offs = i * (font.width + 1) * 4; + var idx = if (char > 0 and char < font.numglyph) blk: { + break :blk font.headersize + (char * font.bytesperglyph); + } else blk: { + break :blk font.headersize + (0 * font.bytesperglyph); + }; + + { + var y: usize = 0; + while (y < font.height) : (y += 1) { + var line = offs; + var mask = @as(u32, 1) << @intCast(u5, font.width - 1); + + { + var x: usize = 0; + while (x < font.width) : (x += 1) { + if ((fontEmbedded[idx] & mask) == 0) { + framebuffer[line / @sizeOf(u32)] = 0x000000; + } else { + framebuffer[line / @sizeOf(u32)] = 0xFFFFFF; + } + mask >>= 1; + line += 4; + } + } + + framebuffer[line / @sizeOf(u32)] = 0; + idx += bytesperline; + offs += bootboot.fb_scanline; + } + } + } +} + +// Entry point, called by BOOTBOOT Loader +export fn _start() callconv(.Naked) noreturn { + // NOTE: this code runs on all cores in parallel + var s = bootboot.fb_scanline; + var w = bootboot.fb_width; + var h = bootboot.fb_height; + var framebuffer = @intToPtr([*]u32, @ptrToInt(&fb)); + + if (s > 0) { + // cross-hair to see screen dimension detected correctly + { + var y: usize = 0; + while (y < h) : (y += 1) { + framebuffer[(s * y + w * 2) / @sizeOf(u32)] = 0x00FFFFFF; + } + } + + { + var x: usize = 0; + while (x < w) : (x += 1) { + framebuffer[(s * (h / 2) + x * 4) / @sizeOf(u32)] = 0x00FFFFFF; + } + } + + // red, green, blue boxes in order + { + var y: usize = 0; + while (y < 20) : (y += 1) { + var x: usize = 0; + while (x < 20) : (x += 1) { + framebuffer[(s * (y + 20) + (x + 20) * 4) / @sizeOf(u32)] = 0x00FF0000; + } + } + } + + { + var y: usize = 0; + while (y < 20) : (y += 1) { + var x: usize = 0; + while (x < 20) : (x += 1) { + framebuffer[(s * (y + 20) + (x + 50) * 4) / @sizeOf(u32)] = 0x0000FF00; + } + } + } + + { + var y: usize = 0; + while (y < 20) : (y += 1) { + var x: usize = 0; + while (x < 20) : (x += 1) { + framebuffer[(s * (y + 20) + (x + 80) * 4) / @sizeOf(u32)] = 0x000000FF; + } + } + } + + // say hello + puts("Hello from a simple BOOTBOOT kernel"); + } + // hang for now + while (true) {} +}