diff --git a/README.md b/README.md index 44bacba..fc2edc7 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,21 @@ slowly porting from rust. - interrupts - terminal console - lspci - - todo: memory mapping - - todo: cfs scheduler - - todo: smp ### dependencies -`ziglang` compiler +`zig` compiler ### compile -`zig build` compile and links a multiboot kernel, without a bootloader. +`zig build` compiles and links the multiboot kernel, without a bootloader. ### test -`./run.sh qemu start` -`./run.sh qemu monitor` -`./run.sh gdb` +`./qemu.sh start` +`./qemu.sh monitor` +`./qemu.sh gdb` + +### todo + +- recycling allocator that wraps the bump allocator diff --git a/qemu.sh b/qemu.sh index 42d7128..d989ffd 100755 --- a/qemu.sh +++ b/qemu.sh @@ -9,8 +9,10 @@ start() { -gdb tcp::${QEMU_GDB_PORT} \ -monitor unix:${QEMU_SOCKET},server,nowait \ -enable-kvm \ - -m 547M \ + -m 1337M \ -display curses \ + -serial mon:stdio \ + -append "Hello" \ -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \ -kernel ${KERNEL} # build/kernel.iso diff --git a/src/arch/x86/main.zig b/src/arch/x86/main.zig index 1a473ba..5adcdf4 100644 --- a/src/arch/x86/main.zig +++ b/src/arch/x86/main.zig @@ -5,12 +5,14 @@ const mem = @import("mem.zig"); const gdt = @import("gdt.zig"); const x86 = @import("lib/index.zig"); const console = @import("../console.zig"); +const printf = @import("../../vga.zig").printf; /// x86 specific intialization /// first entry point (see linker.ld) pub fn x86_main(info: *const MultibootInfo) void { - mem.initialize(info); + var allocator = mem.initialize(info); + // gdt.initialize(); idt.initialize(); - // x86.sti(); + x86.sti(); } diff --git a/src/arch/x86/mem.zig b/src/arch/x86/mem.zig index 8f6d081..4c4cd9a 100644 --- a/src/arch/x86/mem.zig +++ b/src/arch/x86/mem.zig @@ -1,30 +1,157 @@ usingnamespace @import("kernel").multiboot; const assert = @import("std").debug.assert; const vga = @import("../../vga.zig"); +const std = @import("std"); +const printf = @import("../../vga.zig").printf; -pub fn initialize(info: *const MultibootInfo) void { +pub fn initialize(info: *const MultibootInfo) bumpAllocator { assert((info.flags & MULTIBOOT_INFO_MEMORY) != 0); assert((info.flags & MULTIBOOT_INFO_MEM_MAP) != 0); + format_multibootinfo(info); + return bumpAllocator.new(info); +} + +pub fn format_multibootentry(entry: *MultibootMMapEntry) void { + if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) { + vga.printf("AVAILABLE: "); + } else { + vga.printf("NOT AVAILABLE: "); + } + vga.printf("{x} ", entry.addr); + if (entry.len / (1024 * 1024) > 0) { + vga.printf("({} MB)\n", entry.len / (1024 * 1024)); + } else { + vga.printf("({} kB)\n", entry.len / (1024)); + } +} + +pub fn format_multibootinfo(info: *const MultibootInfo) void { + var cmdline_ptr = @intToPtr([*c]const u8, info.cmdline); + var cmdline = @ptrCast([*c]const u8, cmdline_ptr); + // var cmdline = std.cstr.toSliceConst(info.cmdline); vga.printf("lower: {x}\n", info.mem_lower); vga.printf("upper: {x}\n", info.mem_upper); vga.printf("mmap_l: {}\n", info.mmap_length); vga.printf("mmap_a: {x}\n", info.mmap_addr); + vga.printf("cmdline: {x}\n", cmdline_ptr); + vga.printf("cmdline: {}\n", cmdline); var map: usize = info.mmap_addr; while (map < info.mmap_addr + info.mmap_length) { var entry = @intToPtr(*MultibootMMapEntry, map); - if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) { - vga.printf("AVAILABLE: "); - } else { - vga.printf("NOT AVAILABLE: "); - } - vga.printf("{x} ", entry.addr); - if (entry.len / (1024 * 1024) > 0) { - vga.printf("({} MB)\n", entry.len / (1024 * 1024)); - } else { - vga.printf("({} kB)\n", entry.len / (1024)); - } + format_multibootentry(entry); map += entry.size + @sizeOf(@typeOf(entry.size)); } } + +// returns each available physical frame one by one in order +pub const bumpAllocator = struct { + next_free_frame: physFrame, + current_area: ?*MultibootMMapEntry, + info: *const MultibootInfo, + + pub fn new(info: *const MultibootInfo) bumpAllocator { + const first_area = @intToPtr(*MultibootMMapEntry, info.mmap_addr); + var allocator = bumpAllocator{ + .current_area = first_area, + .next_free_frame = physFrame.from_addr(first_area.addr), + .info = info, + }; + // allocator.choose_next_area(); + return allocator; + } + + pub fn allocate(self: var, count: u64) ?physFrame { + if (count == 0) { + return null; + } + if (self.current_area == null) { + return null; + } + if (self.current_area.?.type != MULTIBOOT_MEMORY_AVAILABLE) { + self.choose_next_area(); + return self.allocate(count); + } + + const start_frame = self.next_free_frame; + const end_frame = self.next_free_frame.add(count - 1); + const current_area_last_frame = physFrame.from_addr(self.current_area.?.addr + self.current_area.?.len); + if (end_frame.number > current_area_last_frame.number) { + self.choose_next_area(); + return self.allocate(count); + } + self.next_free_frame.number += count; + return start_frame; + } + + pub fn choose_next_area(self: var) void { + printf("choosing next area\n"); + const current = self.current_area.?; + var next_area = @ptrToInt(current) + current.size + @sizeOf(@typeOf(current)); + if (next_area >= self.info.mmap_addr + self.info.mmap_length) { + self.current_area = null; + } else { + format_multibootentry(self.current_area.?); + self.current_area = @intToPtr(*MultibootMMapEntry, next_area); + format_multibootentry(self.current_area.?); + self.next_free_frame = physFrame.from_addr(self.current_area.?.addr); + } + } +}; + +pub const PAGE_SIZE = 4096; + +pub const physFrame = struct { + number: u64, + + pub fn from_addr(addr: u64) physFrame { + return physFrame{ .number = @divTrunc(addr, PAGE_SIZE) }; + } + + pub fn add(self: physFrame, count: u64) physFrame { + return physFrame{ .number = self.number + count }; + } + + pub fn start_addr(self: physFrame) u64 { + return (self.number * PAGE_SIZE); + } +}; + +const PageDirectory = packed struct { + entries: [1024]PageDirectoryEntry, +}; + +const PageDirectoryEntry = packed struct { + address: u21, + available: u2, + ignored: u1, + size: u1, + zero: u1, + accessed: u1, + cache_disabled: u1, + write_through: u1, + user: u1, + writeable: u1, + present: u1, +}; + +const PageTable = packed struct { + entries: [1024]PageTableEntry, +}; + +const PageTableEntry = packed struct { + address: u21, + available: u2, + global: u1, + zero: u1, + dirty: u1, + accessed: u1, + cache_disabled: u1, + write_through: u1, + user: u1, + writeable: u1, + present: u1, +}; + +// assert(@sizeOf(PageTableEntry) == 32); diff --git a/src/main.zig b/src/main.zig index 0f5d27d..fc192d0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,8 +1,8 @@ usingnamespace @import("multiboot.zig"); +usingnamespace @import("vga.zig"); const pci = @import("pci.zig"); const arch = @import("arch/x86/lib/index.zig"); const console = @import("console.zig"); -const vga = @import("vga.zig"); const x86 = @import("arch/x86/main.zig"); const assert = @import("std").debug.assert; @@ -11,11 +11,23 @@ export fn kmain(magic: u32, info: *const MultibootInfo) noreturn { assert(magic == MULTIBOOT_BOOTLOADER_MAGIC); console.initialize(); - vga.printf("--- x86_main ---\n"); + printf("--- hello x86_main ---\n"); x86.x86_main(info); - vga.printf("--- arch indepent boot ---\n"); + // pagefault_test(0xfeffc000); + + printf("\n--- arch indepent boot ---\n"); while (true) {} } + +fn pagefault_test(addr: u32) void { + const ptr = @intToPtr(*volatile u8, addr); + var a: u8 = ptr.*; + printf("a = {}\n", a); + + ptr.* += 1; + + printf("a = {}\n", ptr.*); +} diff --git a/src/multiboot.zig b/src/multiboot.zig index 7ea2ed4..d2630d0 100644 --- a/src/multiboot.zig +++ b/src/multiboot.zig @@ -1,3 +1,6 @@ +// MULTIBOOT1 +// https://www.gnu.org/software/grub/manual/multiboot/multiboot.html + // zig fmt: off const tty = @import("tty.zig"); const cstr = @import("std").cstr; @@ -117,7 +120,8 @@ export const multiboot_header align(4) linksection(".multiboot") = multiboot: { const MAGIC = u32(0x1BADB002); // multiboot magic const ALIGN = u32(1 << 0); // Align loaded modules. const MEMINFO = u32(1 << 1); // Receive a memory map from the bootloader. - const FLAGS = ALIGN | MEMINFO; // Combine the flags. + const CMDLINE = u32(1 << 2); // Receive a cmdline from the bootloader + const FLAGS = ALIGN | MEMINFO | CMDLINE; // Combine the flags. break :multiboot MultibootHeader { .magic = MAGIC,