cleaning up before kmalloc
This commit is contained in:
parent
902aa136c6
commit
5880d5296e
16 changed files with 119 additions and 84 deletions
33
README.md
33
README.md
|
|
@ -1,36 +1,33 @@
|
|||
## hobby kernel in zig
|
||||
|
||||
slowly porting from rust.
|
||||
# hobby kernel in zig
|
||||
|
||||
### features
|
||||
|
||||
- vga frame buffer
|
||||
- 80x25 frame buffer
|
||||
- ps2 keyboard driver
|
||||
- interrupts
|
||||
- terminal console
|
||||
- lspci
|
||||
- x86
|
||||
- MMU
|
||||
- interrupts
|
||||
|
||||
### 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`
|
||||
`./qemu.sh monitor`
|
||||
`./qemu.sh gdb`
|
||||
## test
|
||||
|
||||
- `./qemu.sh start`
|
||||
- `./qemu.sh monitor`
|
||||
- `./qemu.sh gdb`
|
||||
|
||||
# Notes
|
||||
|
||||
## interrupts
|
||||
## interrupt call chain
|
||||
|
||||
`interrupt` -> `idt[n]` -> `isrN` -> `isrDispatch` -> `handlers[n]` (default `unhandled()`)
|
||||
|
||||
## layout
|
||||
|
||||
`0->4Mib` kernel reserved
|
||||
`1Mib` interrupt stack
|
||||
|
|
|
|||
2
qemu.sh
2
qemu.sh
|
|
@ -18,7 +18,7 @@ start() {
|
|||
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
||||
# 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...
|
||||
# -serial mon:stdio \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ pub fn initialize() void {
|
|||
isr.install_irqs();
|
||||
isr.install_syscalls();
|
||||
interrupt.registerIRQ(0, interrupt.pit_handler);
|
||||
interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||
|
||||
// load IDT
|
||||
lidt(@ptrToInt(&idtr));
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
// std
|
||||
pub const assert = @import("std").debug.assert;
|
||||
|
||||
// from core kernel
|
||||
pub usingnamespace @import("../../vga.zig");
|
||||
pub const multiboot = @import("../../multiboot.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/instructions.zig");
|
||||
pub usingnamespace @import("main.zig");
|
||||
|
||||
pub const layout = @import("layout.zig");
|
||||
pub const memory = @import("memory.zig");
|
||||
pub const paging = @import("paging.zig");
|
||||
pub const idt = @import("idt.zig");
|
||||
pub const isr = @import("isr.zig");
|
||||
pub const gdt = @import("gdt.zig");
|
||||
pub const interrupt = @import("interrupt.zig");
|
||||
|
||||
pub const assert = @import("std").debug.assert;
|
||||
|
|
|
|||
|
|
@ -175,11 +175,8 @@ pub fn maskIRQ(irq: u8, mask: bool) void {
|
|||
|
||||
// Mask or unmask the interrupt.
|
||||
const shift = @intCast(u3, irq % 8);
|
||||
if (mask) {
|
||||
outb(port, old | (u8(1) << shift));
|
||||
} else {
|
||||
outb(port, old & ~(u8(1) << shift));
|
||||
}
|
||||
if (mask) outb(port, old | (u8(1) << shift));
|
||||
if (!mask) outb(port, old & ~(u8(1) << shift));
|
||||
const new = inb(port); // Retrieve the current mask.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
//https://wiki.osdev.org/Memory_Map_(x86)
|
||||
|
||||
const kiB = 1024;
|
||||
const MiB = 1024 * kiB; // 0x100000
|
||||
const GiB = 1024 * MiB;
|
||||
|
||||
// zig fmt: off
|
||||
pub const KSTACK = 0x80000; // todo: move to .bss
|
||||
pub const KERNEL = 0x100000;
|
||||
pub const IDENTITY = 0x400000; // 0->4MiB
|
||||
pub const HEAP = 0x800000;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -8,27 +8,31 @@ pub var stack_size: usize = undefined;
|
|||
pub var stack_end: usize = undefined;
|
||||
|
||||
pub const PAGE_SIZE: usize = 4096;
|
||||
pub inline fn pageAlign(address: u32) u32 {
|
||||
// 4095 -> 4096
|
||||
// 4096 -> 4096
|
||||
// 4097 -> 8192
|
||||
pub fn pageAlign(address: u32) u32 {
|
||||
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
|
||||
////
|
||||
// Return the amount of variable elements (in bytes).
|
||||
//
|
||||
pub fn available() usize {
|
||||
pub inline fn available() usize {
|
||||
return stack_index * PAGE_SIZE;
|
||||
}
|
||||
|
||||
pub inline fn available_MiB() usize {
|
||||
return available() / (1024 * 1024);
|
||||
}
|
||||
|
||||
////
|
||||
// Request a free physical page and return its address.
|
||||
//
|
||||
pub fn allocate() ?usize {
|
||||
pub fn allocate() !usize {
|
||||
if (available() == 0) {
|
||||
println("out of memory");
|
||||
return null;
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
stack_index -= 1;
|
||||
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_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.
|
||||
stack = @intToPtr([*]usize, 0x200000);
|
||||
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
|
||||
|
||||
// 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_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);
|
||||
}
|
||||
|
||||
pub fn introspect() void {
|
||||
println("physframes left: {d} ({d} MiB)", stack_index, available_MiB());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ fn pageFault() void {
|
|||
while (true) asm volatile ("hlt");
|
||||
}
|
||||
|
||||
fn pageBase(addr: usize) usize {
|
||||
inline fn pageBase(addr: usize) usize {
|
||||
return addr & (~PAGE_SIZE +% 1);
|
||||
}
|
||||
fn pde(addr: usize) *PageEntry {
|
||||
inline fn pde(addr: usize) *PageEntry {
|
||||
return &PD[addr >> 22];
|
||||
}
|
||||
fn pte(addr: usize) *PageEntry {
|
||||
inline fn pte(addr: usize) *PageEntry {
|
||||
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);
|
||||
if (pde.* == 0) pde.* = memory.allocate() | WRITE | PRESENT;
|
||||
if (pde.* == 0) pde.* = try memory.allocate() | WRITE | PRESENT;
|
||||
var pte: *PageEntry = pte(virt);
|
||||
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;
|
||||
i = 0;
|
||||
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]));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ var command: [10]u8 = undefined;
|
|||
var command_len: usize = 0;
|
||||
|
||||
fn execute(com: []u8) void {
|
||||
if (@import("std").mem.eql(u8, com, "lspci")) pci.lspci();
|
||||
if (@import("std").mem.eql(u8, com, "paging")) x86.paging.addrspace();
|
||||
if (@import("std").mem.eql(u8, com, "uptime")) time.uptime();
|
||||
if (@import("std").mem.eql(u8, com, "topbar")) topbar();
|
||||
const eql = std.mem.eql;
|
||||
if (eql(u8, com, "x86paging")) return x86.paging.introspect();
|
||||
if (eql(u8, com, "x86memory")) return x86.memory.introspect();
|
||||
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 {
|
||||
|
|
@ -15,7 +18,7 @@ pub fn keypress(char: u8) void {
|
|||
switch (char) {
|
||||
'\n' => {
|
||||
print("\n");
|
||||
execute(command[0..command_len]);
|
||||
if (command_len > 0) execute(command[0..command_len]);
|
||||
print("> ");
|
||||
command_len = 0;
|
||||
},
|
||||
|
|
@ -38,6 +41,6 @@ pub fn keypress(char: u8) void {
|
|||
}
|
||||
|
||||
pub fn initialize() void {
|
||||
x86.interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||
ps2.keyboard_callback = keypress;
|
||||
print("> ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
pub const assert = @import("std").debug.assert;
|
||||
// std
|
||||
pub const std = @import("std");
|
||||
pub const assert = std.debug.assert;
|
||||
|
||||
// main namespace
|
||||
pub usingnamespace @import("vga.zig");
|
||||
pub const x86 = @import("arch/x86/index.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 pci = @import("pci/pci.zig");
|
||||
pub const ps2 = @import("ps2.zig");
|
||||
pub const x86 = @import("arch/x86/index.zig");
|
||||
pub const time = @import("time.zig");
|
||||
|
|
|
|||
|
|
@ -26,5 +26,7 @@ export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
|||
pci.scan();
|
||||
console.initialize();
|
||||
|
||||
// const t = task.Task.new(@ptrToInt(topbar));
|
||||
|
||||
while (true) asm volatile ("hlt");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(address: usize) void {}
|
||||
|
||||
pub fn free() {
|
||||
}
|
||||
pub fn initialize() void {}
|
||||
|
|
|
|||
|
|
@ -54,9 +54,11 @@ pub const PciDevice = struct {
|
|||
var drv = Drivers[i];
|
||||
if (self.class() != drv.class or self.subclass() != drv.subclass)
|
||||
continue;
|
||||
if (drv.vendor) |v| if (self.vendor != v)
|
||||
if (drv.vendor) |v|
|
||||
if (self.vendor != v)
|
||||
continue;
|
||||
if (drv.subsystem) |ss| if (self.subsystem() != ss)
|
||||
if (drv.subsystem) |ss|
|
||||
if (self.subsystem() != ss)
|
||||
continue;
|
||||
return drv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,9 +78,13 @@ fn key_isrelease(scancode: u8) bool {
|
|||
return scancode & (1 << 7) != 0;
|
||||
}
|
||||
|
||||
pub var keyboard_callback: fn (u8) void = undefined;
|
||||
|
||||
pub fn keyboard_handler() void {
|
||||
const scancode = ps2_scancode();
|
||||
if (scancode > KEYMAP_US.len) return;
|
||||
if (key_isrelease(scancode)) return; // don't process releases
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ pub fn increment(value: u32) void {
|
|||
|
||||
pub fn uptime() void {
|
||||
const offset_ms = offset_us / 1000;
|
||||
println("uptime: {}.{:.3}", offset_s, offset_ms);
|
||||
println("{}.{:.3}", offset_s, offset_ms);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
const time = @import("time.zig");
|
||||
const x86 = @import("arch/x86/index.zig");
|
||||
const std = @import("std");
|
||||
|
||||
// Screen size.
|
||||
pub const VGA_WIDTH = 80;
|
||||
pub const VGA_HEIGHT = 25;
|
||||
|
|
@ -70,8 +69,7 @@ pub fn topbar() void {
|
|||
vga.cursor = 0;
|
||||
vga.background = Color.Red;
|
||||
|
||||
const offset_ms = time.offset_us / 1000;
|
||||
println("{}.{}", time.offset_s, offset_ms / 10);
|
||||
time.uptime();
|
||||
|
||||
vga.cursor = cursor;
|
||||
vga.background = bg;
|
||||
|
|
@ -154,10 +152,12 @@ const VGA = struct {
|
|||
//
|
||||
fn scrollDown(self: *VGA) void {
|
||||
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.
|
||||
|
||||
// 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.
|
||||
std.mem.set(VGAEntry, self.vram[last..VGA_SIZE], self.entry(' '));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue