From bd12f0495fd6f481b7937a6bc3ed2753e04fc316 Mon Sep 17 00:00:00 2001 From: Jack Halford Date: Fri, 23 Aug 2019 22:30:41 +0200 Subject: [PATCH] changes imports again... --- build.zig | 1 + qemu.sh | 2 +- src/arch/x86/lib/io.zig | 4 ++ src/arch/x86/start.s | 16 +++++ src/base.zig | 4 ++ src/main.zig | 37 +++++----- src/pci/pci.zig | 154 ++++++++++++++++++++++++++++++++++++++++ src/pci/virtio.zig | 23 ++++++ 8 files changed, 223 insertions(+), 18 deletions(-) create mode 100644 src/arch/x86/start.s create mode 100644 src/base.zig create mode 100644 src/pci/pci.zig create mode 100644 src/pci/virtio.zig diff --git a/build.zig b/build.zig index 6794a81..39c2928 100644 --- a/build.zig +++ b/build.zig @@ -7,6 +7,7 @@ pub fn build(b: *Builder) void { kernel.addPackagePath("x86", "src/arch/x86/index.zig"); kernel.setOutputDir("build"); + kernel.addAssemblyFile("src/arch/x86/start.s"); kernel.addAssemblyFile("src/arch/x86/gdt.s"); kernel.addAssemblyFile("src/arch/x86/isr.s"); kernel.addAssemblyFile("src/arch/x86/paging.s"); diff --git a/qemu.sh b/qemu.sh index ee36123..950dbb8 100755 --- a/qemu.sh +++ b/qemu.sh @@ -12,8 +12,8 @@ start() { -m 1337M \ -curses \ -append "Hello" \ + -drive file=disk.img,if=virtio\ -kernel ${KERNEL} - # -drive file=disk.img,if=virtio\ # -no-reboot \ # -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \ # build/kernel.iso diff --git a/src/arch/x86/lib/io.zig b/src/arch/x86/lib/io.zig index 70aac62..f45b3ca 100644 --- a/src/arch/x86/lib/io.zig +++ b/src/arch/x86/lib/io.zig @@ -4,12 +4,14 @@ pub inline fn inb(port: u16) u8 { : [port] "N{dx}" (port) ); } + pub inline fn inw(port: u16) u16 { return asm volatile ("inw %[port], %[result]" : [result] "={ax}" (-> u16) : [port] "N{dx}" (port) ); } + pub inline fn inl(port: u16) u32 { return asm volatile ("inl %[port], %[result]" : [result] "={eax}" (-> u32) @@ -24,6 +26,7 @@ pub inline fn outb(port: u16, value: u8) void { [port] "N{dx}" (port) ); } + pub inline fn outw(port: u16, value: u16) void { asm volatile ("outw %[value], %[port]" : @@ -31,6 +34,7 @@ pub inline fn outw(port: u16, value: u16) void { [port] "N{dx}" (port) ); } + pub inline fn outl(port: u16, value: u32) void { asm volatile ("outl %[value], %[port]" : diff --git a/src/arch/x86/start.s b/src/arch/x86/start.s new file mode 100644 index 0000000..db987e0 --- /dev/null +++ b/src/arch/x86/start.s @@ -0,0 +1,16 @@ +.global __start +.type __start, @function + +// Entry point. It puts the machine into a consistent state, +// starts the kernel and then waits forever. +__start: + mov $0x80000, %esp // Setup the stack. + + push %ebx // Pass multiboot info structure. + push %eax // Pass multiboot magic code. + + call kmain // Call the kernel. + + // Halt the CPU. + cli + hlt diff --git a/src/base.zig b/src/base.zig new file mode 100644 index 0000000..7e89379 --- /dev/null +++ b/src/base.zig @@ -0,0 +1,4 @@ +pub const assert = @import("std").debug.assert; +pub const std = @import("std"); + +pub usingnamespace @import("vga.zig"); diff --git a/src/main.zig b/src/main.zig index fff5250..3a0e203 100644 --- a/src/main.zig +++ b/src/main.zig @@ -16,28 +16,31 @@ export const multiboot_header align(4) linksection(".multiboot") = multiboot: { }; }; -export var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined; -const stack_bytes_slice = stack_bytes[0..]; +// export var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined; +// const stack_bytes_slice = stack_bytes[0..]; // linker.ld entrypoint -export nakedcc fn __start() noreturn { - // eax -> multiboot magic - const magic: u32 = asm volatile ("" - : [result] "={eax}" (-> u32) - ); - // ebx -> multiboot info - const info: u32 = asm volatile ("" - : [result] "={ebx}" (-> u32) - ); - @newStackCall(stack_bytes_slice, kmain, magic, @intToPtr(*const multiboot.MultibootInfo, info)); - // @newStackCall(stack_bytes_slice, kmain); -} +// export nakedcc fn __start() noreturn { +// // eax -> multiboot magic +// // ebx -> multiboot info +// const magic = asm volatile ("mov %[ret], %eax" +// : [ret] "=" (-> u32) +// ); +// const info = asm volatile ("" +// : [ret] "=" (-> u32) +// ); +// clear(); +// println("--- {x} ---", magic); +// println("--- {x} ---", info); +// // @newStackCall(stack_bytes_slice, kmain, magic, @intToPtr(*const multiboot.MultibootInfo, info)); +// @newStackCall(stack_bytes_slice, kmain, magic); +// // @newStackCall(stack_bytes_slice, kmain); +// } // arch independant initialization -fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { +export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { + assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC); clear(); - println("--- {x} ---", magic); - // assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC); println("--- x86 initialization ---"); x86.x86_main(info); println("--- core initialization ---"); diff --git a/src/pci/pci.zig b/src/pci/pci.zig new file mode 100644 index 0000000..34751e2 --- /dev/null +++ b/src/pci/pci.zig @@ -0,0 +1,154 @@ +pub usingnamespace @import("../index.zig"); +pub const virtio = @import("virtio.zig"); + +const PCI_CONFIG_ADDRESS = 0xCF8; +const PCI_CONFIG_DATA = 0xCFC; + +// https://wiki.osdev.org/Pci +pub const PciAddress = packed struct { + offset: u8, + function: u3, + slot: u5, + bus: u8, + reserved: u7, + enable: u1, +}; + +pub const PciDevice = struct { + bus: u8, + slot: u5, + function: u3, + 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.vendor_id(); + if (dev.vendor == 0xffff) return null; + return dev; + } + + pub fn address(self: PciDevice, offset: u8) u32 { + var addr = PciAddress{ + .enable = 1, + .reserved = 0, + .bus = self.bus, + .slot = self.slot, + .function = self.function, + .offset = offset, + }; + return @bitCast(u32, addr); + } + + pub fn format(self: PciDevice) void { + print("{}:{}.{}", self.bus, self.slot, self.function); + 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(""); + } + + pub fn driver(self: PciDevice) ?Driver { + var i: usize = 0; + while (i < Drivers.len) : (i += 1) { + var drv = Drivers[i]; + if (self.class() != drv.class or self.subclass() != drv.subclass) + continue; + if (drv.vendor) |v| if (self.vendor != v) + continue; + if (drv.subsystem) |ss| if (self.subsystem() != ss) + continue; + return drv; + } + return null; + } + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | vendor ID | device ID | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | command | status | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | revision ID | prog IF | subclass | class | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |cache line size| latency timer | header type | bist | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + pub fn vendor_id(self: PciDevice) u16 { + return self.config_read(u16, 0x0); + } + pub fn device(self: PciDevice) u16 { + return self.config_read(u16, 0x2); + } + pub fn subclass(self: PciDevice) u8 { + return self.config_read(u8, 0xa); + } + pub fn class(self: PciDevice) u8 { + return self.config_read(u8, 0xb); + } + 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(u8, 0x2e); + } + + pub inline fn config_read(self: PciDevice, comptime size: type, comptime offset: u8) size { + // ask for access before reading config + x86.outl(PCI_CONFIG_ADDRESS, self.address(offset)); + switch (size) { + // read the correct size + u8 => return x86.inb(PCI_CONFIG_DATA), + u16 => return x86.inw(PCI_CONFIG_DATA), + u32 => return x86.inl(PCI_CONFIG_DATA), + else => @compileError("pci config space only supports reading u8, u16, u32."), + } + } +}; + +const Driver = struct { + name: [*]u8, + class: u8, + subclass: u8, + vendor: ?u16 = null, + subsystem: ?u16 = null, + init: fn (PciDevice) void, +}; + +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; + // 0..31 + while (slot < 31) : (slot += 1) { + if (PciDevice.init(0, slot, 0)) |dev| { + var function: u3 = 0; + // 0..7 + while (function < 7) : (function += 1) { + if (PciDevice.init(0, slot, function)) |vf| { + if (vf.driver()) |d| d.init(vf); + } + } + } + } +} + +pub fn lspci() void { + var slot: u5 = 0; + println("b:s.f c,s v d drv"); + while (slot < 31) : (slot += 1) { + if (PciDevice.init(0, slot, 0)) |dev| { + var function: u3 = 0; + // 0..7 + while (function < 7) : (function += 1) { + if (PciDevice.init(0, slot, function)) |vf| { + vf.format(); + } + } + } + } +} diff --git a/src/pci/virtio.zig b/src/pci/virtio.zig new file mode 100644 index 0000000..a281317 --- /dev/null +++ b/src/pci/virtio.zig @@ -0,0 +1,23 @@ +usingnamespace @import("pci.zig"); + +pub fn init(dev: PciDevice) void { + println("-- virtio-block init --"); + dev.format(); + assert(dev.header_type() == 0x0); // mass storage device + assert(dev.subsystem() == 0x2); // virtio-block + + const intr_line = dev.config_read(u8, 0x3c); + const intr_pin = dev.config_read(u8, 0x3d); + const min_grant = dev.config_read(u8, 0x3e); + const max_lat = dev.config_read(u8, 0x3f); + println("{x} {} {} {}", intr_line, intr_pin, min_grant, max_lat); + + println("dev features =0x{x}", dev.config_read(u32, 0x10)); + println("guest features=0x{x}", dev.config_read(u32, 0x14)); + println("queue addr =0x{x}", dev.config_read(u32, 0x18)); + println("queue size =0x{x}", dev.config_read(u16, 0x1c)); + println("queue select =0x{x}", dev.config_read(u16, 0x1e)); + println("queue notify =0x{x}", dev.config_read(u16, 0x20)); + println("device status =0x{x}", dev.config_read(u8, 0x22)); + println("isr status =0x{x}", dev.config_read(u8, 0x23)); +}