cleaning up before kmalloc

This commit is contained in:
Jack Halford 2019-11-23 20:30:05 +01:00
parent 902aa136c6
commit 5880d5296e
16 changed files with 119 additions and 84 deletions

View file

@ -1,36 +1,33 @@
## hobby kernel in zig # hobby kernel in zig
slowly porting from rust.
### features ### features
- vga frame buffer - 80x25 frame buffer
- ps2 keyboard driver - ps2 keyboard driver
- interrupts
- terminal console - terminal console
- lspci - lspci
- x86
- MMU
- interrupts
### dependencies ### dependencies
`zig` compiler - [ziglang](https://github.com/ziglang/zig) 0.5.0
### compile # How to
`zig build` compiles and links the multiboot kernel, without a bootloader. ## compile
### test `zig build` compiles and links the multiboot kernel (without a bootloader)
`./qemu.sh start` ## test
`./qemu.sh monitor`
`./qemu.sh gdb` - `./qemu.sh start`
- `./qemu.sh monitor`
- `./qemu.sh gdb`
# Notes # Notes
## interrupts ## interrupt call chain
`interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`) `interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`)
## layout
`0->4Mib` kernel reserved
`1Mib` interrupt stack

View file

@ -18,7 +18,7 @@ start() {
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \ # -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
# build/kernel.iso # build/kernel.iso
# this allows this switch to monitor with ^a-c, but doesn't # this allows to monitor with ^a-c, but doesn't
# play nice with irqs apparently... # play nice with irqs apparently...
# -serial mon:stdio \ # -serial mon:stdio \
} }

View file

@ -58,6 +58,7 @@ pub fn initialize() void {
isr.install_irqs(); isr.install_irqs();
isr.install_syscalls(); isr.install_syscalls();
interrupt.registerIRQ(0, interrupt.pit_handler); interrupt.registerIRQ(0, interrupt.pit_handler);
interrupt.registerIRQ(1, ps2.keyboard_handler);
// load IDT // load IDT
lidt(@ptrToInt(&idtr)); lidt(@ptrToInt(&idtr));

View file

@ -1,16 +1,20 @@
// std
pub const assert = @import("std").debug.assert;
// from core kernel
pub usingnamespace @import("../../vga.zig"); pub usingnamespace @import("../../vga.zig");
pub const multiboot = @import("../../multiboot.zig"); pub const multiboot = @import("../../multiboot.zig");
pub const time = @import("../../time.zig"); pub const time = @import("../../time.zig");
pub const ps2 = @import("../../ps2.zig");
// x86 namespace
pub usingnamespace @import("lib/io.zig"); pub usingnamespace @import("lib/io.zig");
pub usingnamespace @import("lib/instructions.zig"); pub usingnamespace @import("lib/instructions.zig");
pub usingnamespace @import("main.zig"); pub usingnamespace @import("main.zig");
pub const layout = @import("layout.zig");
pub const memory = @import("memory.zig"); pub const memory = @import("memory.zig");
pub const paging = @import("paging.zig"); pub const paging = @import("paging.zig");
pub const idt = @import("idt.zig"); pub const idt = @import("idt.zig");
pub const isr = @import("isr.zig"); pub const isr = @import("isr.zig");
pub const gdt = @import("gdt.zig"); pub const gdt = @import("gdt.zig");
pub const interrupt = @import("interrupt.zig"); pub const interrupt = @import("interrupt.zig");
pub const assert = @import("std").debug.assert;

View file

@ -175,11 +175,8 @@ pub fn maskIRQ(irq: u8, mask: bool) void {
// Mask or unmask the interrupt. // Mask or unmask the interrupt.
const shift = @intCast(u3, irq % 8); const shift = @intCast(u3, irq % 8);
if (mask) { if (mask) outb(port, old | (u8(1) << shift));
outb(port, old | (u8(1) << shift)); if (!mask) outb(port, old & ~(u8(1) << shift));
} else {
outb(port, old & ~(u8(1) << shift));
}
const new = inb(port); // Retrieve the current mask. const new = inb(port); // Retrieve the current mask.
} }

View file

@ -1,6 +1,15 @@
//https://wiki.osdev.org/Memory_Map_(x86) //https://wiki.osdev.org/Memory_Map_(x86)
pub const KSTACK = 0x80000; // todo: move to .bss const kiB = 1024;
pub const KERNEL = 0x100000; const MiB = 1024 * kiB; // 0x100000
pub const IDENTITY = 0x400000; // 0->4MiB const GiB = 1024 * MiB;
pub const HEAP = 0x800000;
// zig fmt: off
pub const KSTACK = 0x80000; // todo: move to .bss
pub const KERNEL = 1 * MiB;
pub const IDENTITY = 4 * MiB; // 0->4MiB
pub const HEAP = 8 * MiB;
pub const USER_STACKS = 0x1000000;
pub const USER_STACKS_END = 0x10000000;
// zig fmt: on

View file

@ -8,27 +8,31 @@ pub var stack_size: usize = undefined;
pub var stack_end: usize = undefined; pub var stack_end: usize = undefined;
pub const PAGE_SIZE: usize = 4096; pub const PAGE_SIZE: usize = 4096;
// 4095 -> 4096 pub inline fn pageAlign(address: u32) u32 {
// 4096 -> 4096 // 4095 -> 4096
// 4097 -> 8192 // 4096 -> 4096
pub fn pageAlign(address: u32) u32 { // 4097 -> 8192
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1); return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
} }
//// ////
// Return the amount of variable elements (in bytes). // Return the amount of variable elements (in bytes).
// //
pub fn available() usize { pub inline fn available() usize {
return stack_index * PAGE_SIZE; return stack_index * PAGE_SIZE;
} }
pub inline fn available_MiB() usize {
return available() / (1024 * 1024);
}
//// ////
// Request a free physical page and return its address. // Request a free physical page and return its address.
// //
pub fn allocate() ?usize { pub fn allocate() !usize {
if (available() == 0) { if (available() == 0) {
println("out of memory"); println("out of memory");
return null; return error.OutOfMemory;
} }
stack_index -= 1; stack_index -= 1;
return stack[stack_index]; return stack[stack_index];
@ -56,9 +60,14 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0); assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0);
assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0); assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
// TODO: WHAT WHY WHAAAAT, must check back here later
// Place stack at 0x200000 so that in the future I trigger a
// random bug and I won't ever know where it came from, great.
stack = @intToPtr([*]usize, 0x200000); // 2 MiB
// Place the stack of free pages after the last Multiboot module. // Place the stack of free pages after the last Multiboot module.
stack = @intToPtr([*]usize, 0x200000);
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr)); // stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
// Calculate the approximate size of the stack based on the amount of total upper memory. // Calculate the approximate size of the stack based on the amount of total upper memory.
stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize); stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize);
stack_end = pageAlign(@ptrToInt(stack) + stack_size); stack_end = pageAlign(@ptrToInt(stack) + stack_size);
@ -83,3 +92,7 @@ pub fn initialize(info: *const multiboot.MultibootInfo) void {
println("available memory: {d} MiB ", available() / 1024 / 1024); println("available memory: {d} MiB ", available() / 1024 / 1024);
} }
pub fn introspect() void {
println("physframes left: {d} ({d} MiB)", stack_index, available_MiB());
}

View file

@ -22,13 +22,13 @@ fn pageFault() void {
while (true) asm volatile ("hlt"); while (true) asm volatile ("hlt");
} }
fn pageBase(addr: usize) usize { inline fn pageBase(addr: usize) usize {
return addr & (~PAGE_SIZE +% 1); return addr & (~PAGE_SIZE +% 1);
} }
fn pde(addr: usize) *PageEntry { inline fn pde(addr: usize) *PageEntry {
return &PD[addr >> 22]; return &PD[addr >> 22];
} }
fn pte(addr: usize) *PageEntry { inline fn pte(addr: usize) *PageEntry {
return &PT[addr >> 12]; return &PT[addr >> 12];
} }
@ -46,14 +46,28 @@ pub fn unmap(virt: usize) void {
} }
} }
pub fn mmap(virt: usize, phys: ?usize) void { pub fn mmap(virt: usize, phys: ?usize) !void {
var pde: *PageEntry = pde(virt); var pde: *PageEntry = pde(virt);
if (pde.* == 0) pde.* = memory.allocate() | WRITE | PRESENT; if (pde.* == 0) pde.* = try memory.allocate() | WRITE | PRESENT;
var pte: *PageEntry = pte(virt); var pte: *PageEntry = pte(virt);
pte.* = if (phys) |p| p else allocate() | PRESENT; pte.* = if (phys) |p| p else allocate() | PRESENT;
} }
pub fn addrspace() void { pub fn initialize() void {
var p2 = pageDirectory[0..];
// identity map 0 -> 4MB
p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
// recursive mapping
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
assert(memory.stack_end < layout.IDENTITY);
interrupt.register(14, pageFault);
setupPaging(@ptrToInt(&pageDirectory[0]));
}
pub fn introspect() void {
var i: usize = 1; var i: usize = 1;
i = 0; i = 0;
while (i < 1024) : (i += 1) { while (i < 1024) : (i += 1) {
@ -67,17 +81,3 @@ pub fn addrspace() void {
} }
} }
} }
pub fn initialize() void {
var p2 = pageDirectory[0..];
// identity map 0 -> 4MB
p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
// recursive mapping
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
assert(memory.stack_end < 0x400000);
interrupt.register(14, pageFault);
setupPaging(@ptrToInt(&pageDirectory[0]));
}

View file

@ -4,10 +4,13 @@ var command: [10]u8 = undefined;
var command_len: usize = 0; var command_len: usize = 0;
fn execute(com: []u8) void { fn execute(com: []u8) void {
if (@import("std").mem.eql(u8, com, "lspci")) pci.lspci(); const eql = std.mem.eql;
if (@import("std").mem.eql(u8, com, "paging")) x86.paging.addrspace(); if (eql(u8, com, "x86paging")) return x86.paging.introspect();
if (@import("std").mem.eql(u8, com, "uptime")) time.uptime(); if (eql(u8, com, "x86memory")) return x86.memory.introspect();
if (@import("std").mem.eql(u8, com, "topbar")) topbar(); if (eql(u8, com, "lspci")) return pci.lspci();
if (eql(u8, com, "uptime")) return time.uptime();
if (eql(u8, com, "topbar")) return topbar();
println("{}: command not found", com);
} }
pub fn keypress(char: u8) void { pub fn keypress(char: u8) void {
@ -15,7 +18,7 @@ pub fn keypress(char: u8) void {
switch (char) { switch (char) {
'\n' => { '\n' => {
print("\n"); print("\n");
execute(command[0..command_len]); if (command_len > 0) execute(command[0..command_len]);
print("> "); print("> ");
command_len = 0; command_len = 0;
}, },
@ -38,6 +41,6 @@ pub fn keypress(char: u8) void {
} }
pub fn initialize() void { pub fn initialize() void {
x86.interrupt.registerIRQ(1, ps2.keyboard_handler); ps2.keyboard_callback = keypress;
print("> "); print("> ");
} }

View file

@ -1,10 +1,14 @@
pub const assert = @import("std").debug.assert; // std
pub const std = @import("std"); pub const std = @import("std");
pub const assert = std.debug.assert;
// main namespace
pub usingnamespace @import("vga.zig"); pub usingnamespace @import("vga.zig");
pub const x86 = @import("arch/x86/index.zig");
pub const multiboot = @import("multiboot.zig"); pub const multiboot = @import("multiboot.zig");
pub const mem = @import("memory.zig");
pub const task = @import("task.zig");
pub const console = @import("console.zig"); pub const console = @import("console.zig");
pub const pci = @import("pci/pci.zig"); pub const pci = @import("pci/pci.zig");
pub const ps2 = @import("ps2.zig"); pub const ps2 = @import("ps2.zig");
pub const x86 = @import("arch/x86/index.zig");
pub const time = @import("time.zig"); pub const time = @import("time.zig");

View file

@ -26,5 +26,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
pci.scan(); pci.scan();
console.initialize(); console.initialize();
// const t = task.Task.new(@ptrToInt(topbar));
while (true) asm volatile ("hlt"); while (true) asm volatile ("hlt");
} }

View file

@ -1,8 +1,7 @@
const paging = @import("arch/x86/paging.zig"); pub usingnamespace @import("index.zig");
pub fn alloc(size: usize) usize { pub fn allocate(comptime T: type) !*type {}
}
pub fn free() { pub fn free(address: usize) void {}
}
pub fn initialize() void {}

View file

@ -54,10 +54,12 @@ pub const PciDevice = struct {
var drv = Drivers[i]; var drv = Drivers[i];
if (self.class() != drv.class or self.subclass() != drv.subclass) if (self.class() != drv.class or self.subclass() != drv.subclass)
continue; continue;
if (drv.vendor) |v| if (self.vendor != v) if (drv.vendor) |v|
continue; if (self.vendor != v)
if (drv.subsystem) |ss| if (self.subsystem() != ss) continue;
continue; if (drv.subsystem) |ss|
if (self.subsystem() != ss)
continue;
return drv; return drv;
} }
return null; return null;
@ -139,7 +141,7 @@ pub fn scan() void {
pub fn lspci() void { pub fn lspci() void {
var slot: u5 = 0; var slot: u5 = 0;
println("b:s.f c,s v d drv"); println("b:s.f c, s v d drv");
while (slot < 31) : (slot += 1) { while (slot < 31) : (slot += 1) {
if (PciDevice.init(0, slot, 0)) |dev| { if (PciDevice.init(0, slot, 0)) |dev| {
var function: u3 = 0; var function: u3 = 0;

View file

@ -78,9 +78,13 @@ fn key_isrelease(scancode: u8) bool {
return scancode & (1 << 7) != 0; return scancode & (1 << 7) != 0;
} }
pub var keyboard_callback: fn (u8) void = undefined;
pub fn keyboard_handler() void { pub fn keyboard_handler() void {
const scancode = ps2_scancode(); const scancode = ps2_scancode();
if (scancode > KEYMAP_US.len) return;
if (key_isrelease(scancode)) return; // don't process releases if (key_isrelease(scancode)) return; // don't process releases
const shift = false; // don't know about modifiers yet const shift = false; // don't know about modifiers yet
console.keypress(KEYMAP_US[scancode][if (shift) 1 else 0]); const character = KEYMAP_US[scancode][if (shift) 1 else 0];
if (keyboard_callback != undefined) keyboard_callback(character);
} }

View file

@ -10,5 +10,5 @@ pub fn increment(value: u32) void {
pub fn uptime() void { pub fn uptime() void {
const offset_ms = offset_us / 1000; const offset_ms = offset_us / 1000;
println("uptime: {}.{:.3}", offset_s, offset_ms); println("{}.{:.3}", offset_s, offset_ms);
} }

View file

@ -2,7 +2,6 @@
const time = @import("time.zig"); const time = @import("time.zig");
const x86 = @import("arch/x86/index.zig"); const x86 = @import("arch/x86/index.zig");
const std = @import("std"); const std = @import("std");
// Screen size. // Screen size.
pub const VGA_WIDTH = 80; pub const VGA_WIDTH = 80;
pub const VGA_HEIGHT = 25; pub const VGA_HEIGHT = 25;
@ -70,8 +69,7 @@ pub fn topbar() void {
vga.cursor = 0; vga.cursor = 0;
vga.background = Color.Red; vga.background = Color.Red;
const offset_ms = time.offset_us / 1000; time.uptime();
println("{}.{}", time.offset_s, offset_ms / 10);
vga.cursor = cursor; vga.cursor = cursor;
vga.background = bg; vga.background = bg;
@ -154,10 +152,12 @@ const VGA = struct {
// //
fn scrollDown(self: *VGA) void { fn scrollDown(self: *VGA) void {
const first = VGA_WIDTH; // Index of first line. const first = VGA_WIDTH; // Index of first line.
const second = 2 * VGA_WIDTH; // Index of first line.
const last = VGA_SIZE - VGA_WIDTH; // Index of last line. const last = VGA_SIZE - VGA_WIDTH; // Index of last line.
// Copy all the screen (apart from the first line) up one line. // Copy all the screen (apart from the first line) up one line.
std.mem.copy(VGAEntry, self.vram[0..last], self.vram[first..VGA_SIZE]); // std.mem.copy(VGAEntry, self.vram[0..last], self.vram[first .. VGA_SIZE]); // whole screen
std.mem.copy(VGAEntry, self.vram[first..last], self.vram[second..VGA_SIZE]); // skip topbar
// Clean the last line. // Clean the last line.
std.mem.set(VGAEntry, self.vram[last..VGA_SIZE], self.entry(' ')); std.mem.set(VGAEntry, self.vram[last..VGA_SIZE], self.entry(' '));