diff --git a/src/arch/x86/idt.zig b/src/arch/x86/idt.zig index b89ae5c..aa471d4 100644 --- a/src/arch/x86/idt.zig +++ b/src/arch/x86/idt.zig @@ -8,6 +8,15 @@ const gdt = @import("gdt.zig"); pub const INTERRUPT_GATE = 0x8E; pub const SYSCALL_GATE = 0xEE; +// Interrupt Descriptor Table. +var idt: [256]IDTEntry = undefined; + +// IDT descriptor register pointing at the IDT. +const idtr = IDTRegister{ + .limit = u16(@sizeOf(@typeOf(idt))), + .base = &idt, +}; + // Structure representing an entry in the IDT. const IDTEntry = packed struct { offset_low: u16, @@ -23,16 +32,6 @@ const IDTRegister = packed struct { base: *[256]IDTEntry, }; -// Interrupt Descriptor Table. -var idt: [256]IDTEntry = undefined; - -// IDT descriptor register pointing at the IDT. -const idtr = IDTRegister{ - .limit = u16(@sizeOf(@typeOf(idt))), - .base = &idt, -}; - -//// // Setup an IDT entry. // // Arguments: @@ -50,9 +49,7 @@ pub fn setGate(n: u8, flags: u8, offset: extern fn () void) void { idt[n].selector = gdt.KERNEL_CODE; } -//// // Initialize the Interrupt Descriptor Table. -// pub fn initialize() void { // configure PIC and set ISRs interrupt.initialize(); diff --git a/src/arch/x86/interrupt.zig b/src/arch/x86/interrupt.zig index 068bb30..67b1257 100644 --- a/src/arch/x86/interrupt.zig +++ b/src/arch/x86/interrupt.zig @@ -164,15 +164,13 @@ fn remapPIC() void { } pub fn maskIRQ(irq: u8, mask: bool) void { - if (irq > 15) { - return; - } + if (irq > 15) return; // Figure out if master or slave PIC owns the IRQ. const port = if (irq < 8) u16(PIC1_DATA) else u16(PIC2_DATA); const old = x86.inb(port); // Retrieve the current mask. // Mask or unmask the interrupt. - const shift = @intCast(u3, irq % 8); // TODO: waiting for Andy to fix this. + const shift = @intCast(u3, irq % 8); if (mask) { x86.outb(port, old | (u8(1) << shift)); } else { diff --git a/src/arch/x86/isr.zig b/src/arch/x86/isr.zig index 90abf13..6714f0e 100644 --- a/src/arch/x86/isr.zig +++ b/src/arch/x86/isr.zig @@ -80,19 +80,6 @@ pub const Registers = packed struct { edx: u32, ecx: u32, eax: u32, - - pub fn init() Registers { - return Registers{ - .edi = 0, - .esi = 0, - .ebp = 0, - .esp = 0, - .ebx = 0, - .edx = 0, - .ecx = 0, - .eax = 0, - }; - } }; // Pointer to the current saved context. diff --git a/src/arch/x86/lib/instructions.zig b/src/arch/x86/lib/instructions.zig index 99d302d..a912abf 100644 --- a/src/arch/x86/lib/instructions.zig +++ b/src/arch/x86/lib/instructions.zig @@ -16,9 +16,7 @@ pub inline fn ltr(desc: u16) void { // pub inline fn hang() noreturn { asm volatile ("cli"); - while (true) { - asm volatile ("hlt"); - } + while (true) asm volatile ("hlt"); } pub inline fn sti() void { diff --git a/src/arch/x86/memory.zig b/src/arch/x86/memory.zig index 0f91948..34f3662 100644 --- a/src/arch/x86/memory.zig +++ b/src/arch/x86/memory.zig @@ -32,7 +32,6 @@ pub fn allocate() ?usize { println("out of memory"); return null; } - stack_index -= 1; return stack[stack_index]; } diff --git a/src/arch/x86/paging.zig b/src/arch/x86/paging.zig index 4d1307d..0c6219a 100644 --- a/src/arch/x86/paging.zig +++ b/src/arch/x86/paging.zig @@ -22,9 +22,7 @@ pub var pageDirectory: [1024]PageEntry align(4096) linksection(".bss") = [_]Page fn pageFault() void { println("pagefault"); - while (true) { - asm volatile ("hlt"); - } + while (true) asm volatile ("hlt"); } fn pageBase(addr: usize) usize { @@ -44,21 +42,17 @@ pub fn translate(virt: usize) ?usize { } pub fn unmap(virt: usize) void { - var pte = pte(virt); - if (pte.* == 0) { + if (translate(virt)) |phys| { + memory.free(translate(virt)); + } else { println("can't unmap 0x{x}, map is empty.", addr); - return; } - pte.* = 0; - memory.free(translate(virt)); } pub fn mmap(virt: usize, phys: ?usize) void { - var pde: *PageEntry = &PD[virt >> 22]; - if (pde.* == 0) { - pde.* = memory.allocate() | WRITE | PRESENT; - } - var pte: *PageEntry = &PT[virt >> 12]; + var pde: *PageEntry = pde(virt); + if (pde.* == 0) pde.* = memory.allocate() | WRITE | PRESENT; + var pte: *PageEntry = pte(virt); pte.* = if (phys) |p| p else allocate() | PRESENT; } @@ -66,35 +60,27 @@ pub fn addrspace() void { var i: usize = 1; i = 0; while (i < 1024) : (i += 1) { - if (PD[i] == 0) { - continue; - } + if (PD[i] == 0) continue; println("p2[{}] -> 0x{x}", i, PD[i]); - if (PD[i] & HUGE != 0) { - continue; - } + if (PD[i] & HUGE != 0) continue; var j: usize = 0; while (j < 1024) : (j += 1) { var entry: PageEntry = PT[i * 1024 + j]; - if (entry != 0) { - println("p2[{}]p1[{}] -> 0x{x}", i, j, entry); - } + if (entry != 0) println("p2[{}]p1[{}] -> 0x{x}", i, j, entry); } } } pub fn initialize() void { var p2 = pageDirectory[0..]; - // identity map 0 -> 4MB + // identity map 0 -> 4MB p2[0] = 0x000000 | PRESENT | WRITE | HUGE; + // recursive mapping p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE; assert(memory.stack_end < 0x400000); - // const first: *u32 = @ptrCast(*u32, p2); - // println("p2[0] {b}", first.*); interrupt.register(14, pageFault); setupPaging(@ptrToInt(&pageDirectory[0])); - // const addr = mapper.translate(0xfffff000); } diff --git a/src/console.zig b/src/console.zig index 3af594a..e166398 100644 --- a/src/console.zig +++ b/src/console.zig @@ -1,7 +1,7 @@ const interrupt = @import("arch/x86/interrupt.zig"); const paging = @import("arch/x86/paging.zig"); const ps2 = @import("ps2.zig"); -// const pci = @import("pci.zig"); +const pci = @import("pci.zig"); const mem = @import("std").mem; usingnamespace @import("vga.zig"); @@ -9,7 +9,7 @@ var command: [10]u8 = undefined; var command_len: usize = 0; fn execute(com: []u8) void { - // if (mem.eql(u8, com, "lspci")) pci.lspci(); + if (mem.eql(u8, com, "lspci")) pci.lspci(); if (mem.eql(u8, com, "paging")) paging.addrspace(); } @@ -17,21 +17,16 @@ pub fn keypress(char: u8) void { // this is a custom "readline" capped at 10 characters switch (char) { '\n' => { - vga.writeChar('\n'); + print("\n"); execute(command[0..command_len]); - vga.writeString("> "); + print("> "); command_len = 0; }, - '\x08' => { - //backspace - return; - }, - '\x00' => { - return; - }, + '\x08' => return, //backspace + '\x00' => return, else => { - if (command_len == 10) - return; + // general case + if (command_len == 10) return; vga.writeChar(char); command[command_len] = char; command_len += 1; diff --git a/src/main.zig b/src/main.zig index f2c8116..b8c4bb6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -8,16 +8,14 @@ const assert = @import("std").debug.assert; // arch independant initialization export fn kmain(magic: u32, info: *const MultibootInfo) noreturn { - clear(); assert(magic == MULTIBOOT_BOOTLOADER_MAGIC); + + clear(); println("--- x86 initialization ---"); - x86.x86_main(info); - println("--- core initialization ---"); pci.scan(); console.initialize(); - while (true) { - asm volatile ("hlt"); - } + + while (true) asm volatile ("hlt"); } diff --git a/src/pci.zig b/src/pci.zig index 9ba38b6..320a6c6 100644 --- a/src/pci.zig +++ b/src/pci.zig @@ -4,7 +4,9 @@ const PCI_CONFIG_ADDRESS = 0xCF8; const PCI_CONFIG_DATA = 0xCFC; usingnamespace @import("vga.zig"); const virtio = @import("virtio.zig"); +const std = @import("std"); +// https://wiki.osdev.org/Pci pub const PciAddress = packed struct { offset: u8, function: u3, @@ -21,12 +23,8 @@ pub const PciDevice = struct { vendor: u16 = undefined, pub fn init(bus: u8, slot: u5, function: u3) ?PciDevice { - var dev = PciDevice{ - .bus = bus, - .slot = slot, - .function = function, - }; - dev.vendor = dev.config_read_word(0); + var dev = PciDevice{ .bus = bus, .slot = slot, .function = function }; + dev.vendor = dev.config_read(u16, 0); if (dev.vendor == 0xffff) return null; return dev; } @@ -45,7 +43,8 @@ pub const PciDevice = struct { pub fn format(self: PciDevice) void { print("{}:{}.{}", self.bus, self.slot, self.function); - print(" {x},{x:2}(0x{x:4}): 0x{x} 0x{x}", self.class(), self.subclass(), self.subsystem(), self.vendor, self.device()); + print(" {x},{x:2}", self.class(), self.subclass()); + print(" 0x{x},0x{x}", self.vendor, self.device()); if (self.driver()) |d| print(" {}", d.name); println(""); @@ -57,48 +56,44 @@ 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() == drv.subsystem.?) + if (drv.subsystem) |ss| if (self.subsystem() != ss) continue; return drv; } return null; } + // all pci device must implement these pub fn device(self: PciDevice) u16 { - return self.config_read_word(2); + return self.config_read(u16, 0x2); } - pub fn subclass(self: PciDevice) u16 { - return self.config_read_byte(10); + pub fn subclass(self: PciDevice) u8 { + return self.config_read(u8, 0xa); } - pub fn class(self: PciDevice) u16 { - return self.config_read_byte(11); + pub fn class(self: PciDevice) u8 { + return self.config_read(u8, 0xb); } - pub fn header_type(self: PciDevice) u16 { - return self.config_read_byte(14); + pub fn header_type(self: PciDevice) u8 { + return self.config_read(u8, 0xe); } + + // only for header_type == 0 pub fn subsystem(self: PciDevice) u16 { - return self.config_read_word(0x2e); + return self.config_read(u8, 0x2e); } - pub fn access(self: PciDevice, offset: u8) void { + pub inline fn config_read(self: PciDevice, comptime size: type, comptime offset: u8) size { + // ask for access before reading config arch.outl(PCI_CONFIG_ADDRESS, self.address(offset)); - } - - pub fn config_read_byte(self: PciDevice, offset: u8) u8 { - self.access(offset); - return (arch.inb(PCI_CONFIG_DATA)); - } - - pub fn config_read_word(self: PciDevice, offset: u8) u16 { - self.access(offset); - return (arch.inw(PCI_CONFIG_DATA)); - } - - pub fn config_read_long(self: PciDevice, offset: u8) u32 { - self.access(offset); - return (arch.inl(PCI_CONFIG_DATA)); + switch (size) { + // read the correct size + u8 => return arch.inb(PCI_CONFIG_DATA), + u16 => return arch.inw(PCI_CONFIG_DATA), + u32 => return arch.inl(PCI_CONFIG_DATA), + else => @compileError("pci config space only supports reading u8, u16, u32."), + } } }; @@ -114,12 +109,15 @@ const Driver = struct { const name = "virtio-blk"; pub var Drivers: [1]Driver = [_]Driver{Driver{ .name = &name, .class = 0x1, .subclass = 0x0, .vendor = 0x1af4, .subsystem = 0x2, .init = virtio.init }}; +// TODO: factor 2 functions when anonymous fn is released pub fn scan() void { var slot: u5 = 0; - while (slot < 31) : (slot += 1) { - if (PciDevice.init(0, slot, 0)) |device| { + // 0..31 + while (slot <= std.math.maxInt(u5)) : (slot += 1) { + if (PciDevice.init(0, slot, 0)) |dev| { var function: u3 = 0; - while (function < 8) : (function += 1) { + // 0..7 + while (function <= std.math.maxInt(u3)) : (function += 1) { if (PciDevice.init(0, slot, function)) |vf| { if (vf.driver()) |d| d.init(vf); } @@ -130,11 +128,13 @@ pub fn scan() void { pub fn lspci() void { var slot: u5 = 0; - println("b:s.f c,s (ss) v d drv"); - while (slot < 31) : (slot += 1) { - if (PciDevice.init(0, slot, 0)) |device| { + println("b:s.f c,s v d drv"); + // 0..31 + while (slot <= std.math.maxInt(u5)) : (slot += 1) { + if (PciDevice.init(0, slot, 0)) |dev| { var function: u3 = 0; - while (function < 8) : (function += 1) { + // 0..7 + while (function <= std.math.maxInt(u3)) : (function += 1) { if (PciDevice.init(0, slot, function)) |vf| { vf.format(); } diff --git a/src/ps2.zig b/src/ps2.zig index dfdf58b..22b76ed 100644 --- a/src/ps2.zig +++ b/src/ps2.zig @@ -69,25 +69,19 @@ const KEYMAP_US = [_][2]u8{ fn ps2_scancode() u8 { var scancode: u8 = 0; - while (true) { - if (x86.inb(PS2_DATA) != scancode) { - scancode = x86.inb(PS2_DATA); - if (scancode > 0) - return scancode; - } - } + while (true) if (x86.inb(PS2_DATA) != scancode) { + scancode = x86.inb(PS2_DATA); + if (scancode > 0) return scancode; + }; } fn key_isrelease(scancode: u8) bool { - return (scancode & 1 << 7 != 0); + return scancode & (1 << 7) != 0; } pub fn keyboard_handler() void { const scancode = ps2_scancode(); - const isrelease = key_isrelease(scancode); - if (isrelease) { - return; - } - const shift = false; + 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]); } diff --git a/src/vga.zig b/src/vga.zig index c516b53..223b70b 100644 --- a/src/vga.zig +++ b/src/vga.zig @@ -3,14 +3,16 @@ const mem = @import("std").mem; const arch = @import("arch/x86/lib/index.zig"); const std = @import("std"); -// VRAM buffer address in physical memory. -pub const VRAM_ADDR = 0xB8000; -pub const VRAM_SIZE = 0x8000; // Screen size. pub const VGA_WIDTH = 80; pub const VGA_HEIGHT = 25; pub const VGA_SIZE = VGA_WIDTH * VGA_HEIGHT; -pub var vga = VGA.init(VRAM_ADDR); +pub var vga = VGA{ + .vram = @intToPtr([*]VGAEntry, 0xb8000)[0..0x4000], + .cursor = 0, + .foreground = Color.Black, + .background = Color.Brown, +}; // Color codes. pub const Color = enum(u4) { @@ -39,17 +41,13 @@ pub const VGAEntry = packed struct { background: Color, }; -//// // Enable hardware cursor. -// pub fn enableCursor() void { outb(0x3D4, 0x0A); outb(0x3D5, 0x00); } -//// // Disable hardware cursor. -// pub fn disableCursor() void { outb(0x3D4, 0x0A); outb(0x3D5, 1 << 5); @@ -72,33 +70,14 @@ fn printCallback(context: void, string: []const u8) Errors!void { } // VGA status. -pub const VGA = struct { +const VGA = struct { vram: []VGAEntry, cursor: usize, foreground: Color, background: Color, - //// - // Initialize the VGA status. - // - // Arguments: - // vram: The address of the VRAM buffer. - // - // Returns: - // A structure holding the VGA status. - // - pub fn init(vram: usize) VGA { - return VGA{ - .vram = @intToPtr([*]VGAEntry, vram)[0..0x4000], - .cursor = 0, - .foreground = Color.Black, - .background = Color.Brown, - }; - } - //// // Clear the screen. - // pub fn clear(self: *VGA) void { mem.set(VGAEntry, self.vram[0..VGA_SIZE], self.entry(' ')); @@ -131,12 +110,9 @@ pub const VGA = struct { self.writeChar(' '); }, // Backspace. - // FIXME: hardcoded 8 here is horrible. - 8 => { + '\x08' => { self.cursor -= 1; - // self.writeChar(' '); self.vram[self.cursor] = self.entry(' '); - // self.cursor -= 1; }, // Any other character. else => { diff --git a/src/virtio.zig b/src/virtio.zig new file mode 100644 index 0000000..3c4e3d8 --- /dev/null +++ b/src/virtio.zig @@ -0,0 +1,21 @@ +usingnamespace @import("vga.zig"); +usingnamespace @import("pci.zig"); +const assert = @import("std").debug.assert; + +pub fn init(pci: PciDevice) void { + println("-- virtio-block init --"); + pci.format(); + assert(pci.header_type() == 0x0); // mass storage device + assert(pci.subsystem() == 0x2); // virtio-block + const intr_line = pci.config_read(u8, 0x3c); + const intr_pin = pci.config_read(u8, 0x3d); + const min_grant = pci.config_read(u8, 0x3e); + const max_lat = pci.config_read(u8, 0x3f); + println("{x} {} {} {}", intr_line, intr_pin, min_grant, max_lat); + println("bar0=0x{x}", pci.config_read(u32, 0x10)); + println("bar1=0x{x}", pci.config_read(u32, 0x14)); + println("bar2=0x{x}", pci.config_read(u32, 0x18)); + println("bar3=0x{x}", pci.config_read(u32, 0x1c)); + println("bar4=0x{x}", pci.config_read(u32, 0x20)); + println("bar5=0x{x}", pci.config_read(u32, 0x24)); +}