added virtio, refactoring untill compiler is fixed

This commit is contained in:
Jack Halford 2019-08-17 23:03:13 +02:00
parent 4c9f4b54d8
commit d051e1b0c8
12 changed files with 112 additions and 163 deletions

View file

@ -8,6 +8,15 @@ const gdt = @import("gdt.zig");
pub const INTERRUPT_GATE = 0x8E; pub const INTERRUPT_GATE = 0x8E;
pub const SYSCALL_GATE = 0xEE; 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. // Structure representing an entry in the IDT.
const IDTEntry = packed struct { const IDTEntry = packed struct {
offset_low: u16, offset_low: u16,
@ -23,16 +32,6 @@ const IDTRegister = packed struct {
base: *[256]IDTEntry, 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. // Setup an IDT entry.
// //
// Arguments: // Arguments:
@ -50,9 +49,7 @@ pub fn setGate(n: u8, flags: u8, offset: extern fn () void) void {
idt[n].selector = gdt.KERNEL_CODE; idt[n].selector = gdt.KERNEL_CODE;
} }
////
// Initialize the Interrupt Descriptor Table. // Initialize the Interrupt Descriptor Table.
//
pub fn initialize() void { pub fn initialize() void {
// configure PIC and set ISRs // configure PIC and set ISRs
interrupt.initialize(); interrupt.initialize();

View file

@ -164,15 +164,13 @@ fn remapPIC() void {
} }
pub fn maskIRQ(irq: u8, mask: bool) void { pub fn maskIRQ(irq: u8, mask: bool) void {
if (irq > 15) { if (irq > 15) return;
return;
}
// Figure out if master or slave PIC owns the IRQ. // Figure out if master or slave PIC owns the IRQ.
const port = if (irq < 8) u16(PIC1_DATA) else u16(PIC2_DATA); const port = if (irq < 8) u16(PIC1_DATA) else u16(PIC2_DATA);
const old = x86.inb(port); // Retrieve the current mask. const old = x86.inb(port); // Retrieve the current mask.
// Mask or unmask the interrupt. // 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) { if (mask) {
x86.outb(port, old | (u8(1) << shift)); x86.outb(port, old | (u8(1) << shift));
} else { } else {

View file

@ -80,19 +80,6 @@ pub const Registers = packed struct {
edx: u32, edx: u32,
ecx: u32, ecx: u32,
eax: 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. // Pointer to the current saved context.

View file

@ -16,9 +16,7 @@ pub inline fn ltr(desc: u16) void {
// //
pub inline fn hang() noreturn { pub inline fn hang() noreturn {
asm volatile ("cli"); asm volatile ("cli");
while (true) { while (true) asm volatile ("hlt");
asm volatile ("hlt");
}
} }
pub inline fn sti() void { pub inline fn sti() void {

View file

@ -32,7 +32,6 @@ pub fn allocate() ?usize {
println("out of memory"); println("out of memory");
return null; return null;
} }
stack_index -= 1; stack_index -= 1;
return stack[stack_index]; return stack[stack_index];
} }

View file

@ -22,9 +22,7 @@ pub var pageDirectory: [1024]PageEntry align(4096) linksection(".bss") = [_]Page
fn pageFault() void { fn pageFault() void {
println("pagefault"); println("pagefault");
while (true) { while (true) asm volatile ("hlt");
asm volatile ("hlt");
}
} }
fn pageBase(addr: usize) usize { fn pageBase(addr: usize) usize {
@ -44,21 +42,17 @@ pub fn translate(virt: usize) ?usize {
} }
pub fn unmap(virt: usize) void { pub fn unmap(virt: usize) void {
var pte = pte(virt); if (translate(virt)) |phys| {
if (pte.* == 0) {
println("can't unmap 0x{x}, map is empty.", addr);
return;
}
pte.* = 0;
memory.free(translate(virt)); memory.free(translate(virt));
} else {
println("can't unmap 0x{x}, map is empty.", addr);
}
} }
pub fn mmap(virt: usize, phys: ?usize) void { pub fn mmap(virt: usize, phys: ?usize) void {
var pde: *PageEntry = &PD[virt >> 22]; var pde: *PageEntry = pde(virt);
if (pde.* == 0) { if (pde.* == 0) pde.* = memory.allocate() | WRITE | PRESENT;
pde.* = memory.allocate() | WRITE | PRESENT; var pte: *PageEntry = pte(virt);
}
var pte: *PageEntry = &PT[virt >> 12];
pte.* = if (phys) |p| p else allocate() | PRESENT; pte.* = if (phys) |p| p else allocate() | PRESENT;
} }
@ -66,35 +60,27 @@ pub fn addrspace() void {
var i: usize = 1; var i: usize = 1;
i = 0; i = 0;
while (i < 1024) : (i += 1) { while (i < 1024) : (i += 1) {
if (PD[i] == 0) { if (PD[i] == 0) continue;
continue;
}
println("p2[{}] -> 0x{x}", i, PD[i]); println("p2[{}] -> 0x{x}", i, PD[i]);
if (PD[i] & HUGE != 0) { if (PD[i] & HUGE != 0) continue;
continue;
}
var j: usize = 0; var j: usize = 0;
while (j < 1024) : (j += 1) { while (j < 1024) : (j += 1) {
var entry: PageEntry = PT[i * 1024 + j]; var entry: PageEntry = PT[i * 1024 + j];
if (entry != 0) { if (entry != 0) println("p2[{}]p1[{}] -> 0x{x}", i, j, entry);
println("p2[{}]p1[{}] -> 0x{x}", i, j, entry);
}
} }
} }
} }
pub fn initialize() void { pub fn initialize() void {
var p2 = pageDirectory[0..]; var p2 = pageDirectory[0..];
// identity map 0 -> 4MB
// identity map 0 -> 4MB
p2[0] = 0x000000 | PRESENT | WRITE | HUGE; p2[0] = 0x000000 | PRESENT | WRITE | HUGE;
// recursive mapping
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE; p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
assert(memory.stack_end < 0x400000); assert(memory.stack_end < 0x400000);
// const first: *u32 = @ptrCast(*u32, p2);
// println("p2[0] {b}", first.*);
interrupt.register(14, pageFault); interrupt.register(14, pageFault);
setupPaging(@ptrToInt(&pageDirectory[0])); setupPaging(@ptrToInt(&pageDirectory[0]));
// const addr = mapper.translate(0xfffff000);
} }

View file

@ -1,7 +1,7 @@
const interrupt = @import("arch/x86/interrupt.zig"); const interrupt = @import("arch/x86/interrupt.zig");
const paging = @import("arch/x86/paging.zig"); const paging = @import("arch/x86/paging.zig");
const ps2 = @import("ps2.zig"); const ps2 = @import("ps2.zig");
// const pci = @import("pci.zig"); const pci = @import("pci.zig");
const mem = @import("std").mem; const mem = @import("std").mem;
usingnamespace @import("vga.zig"); usingnamespace @import("vga.zig");
@ -9,7 +9,7 @@ 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 (mem.eql(u8, com, "lspci")) pci.lspci(); if (mem.eql(u8, com, "lspci")) pci.lspci();
if (mem.eql(u8, com, "paging")) paging.addrspace(); 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 // this is a custom "readline" capped at 10 characters
switch (char) { switch (char) {
'\n' => { '\n' => {
vga.writeChar('\n'); print("\n");
execute(command[0..command_len]); execute(command[0..command_len]);
vga.writeString("> "); print("> ");
command_len = 0; command_len = 0;
}, },
'\x08' => { '\x08' => return, //backspace
//backspace '\x00' => return,
return;
},
'\x00' => {
return;
},
else => { else => {
if (command_len == 10) // general case
return; if (command_len == 10) return;
vga.writeChar(char); vga.writeChar(char);
command[command_len] = char; command[command_len] = char;
command_len += 1; command_len += 1;

View file

@ -8,16 +8,14 @@ const assert = @import("std").debug.assert;
// arch independant initialization // arch independant initialization
export fn kmain(magic: u32, info: *const MultibootInfo) noreturn { export fn kmain(magic: u32, info: *const MultibootInfo) noreturn {
clear();
assert(magic == MULTIBOOT_BOOTLOADER_MAGIC); assert(magic == MULTIBOOT_BOOTLOADER_MAGIC);
clear();
println("--- x86 initialization ---"); println("--- x86 initialization ---");
x86.x86_main(info); x86.x86_main(info);
println("--- core initialization ---"); println("--- core initialization ---");
pci.scan(); pci.scan();
console.initialize(); console.initialize();
while (true) {
asm volatile ("hlt"); while (true) asm volatile ("hlt");
}
} }

View file

@ -4,7 +4,9 @@ const PCI_CONFIG_ADDRESS = 0xCF8;
const PCI_CONFIG_DATA = 0xCFC; const PCI_CONFIG_DATA = 0xCFC;
usingnamespace @import("vga.zig"); usingnamespace @import("vga.zig");
const virtio = @import("virtio.zig"); const virtio = @import("virtio.zig");
const std = @import("std");
// https://wiki.osdev.org/Pci
pub const PciAddress = packed struct { pub const PciAddress = packed struct {
offset: u8, offset: u8,
function: u3, function: u3,
@ -21,12 +23,8 @@ pub const PciDevice = struct {
vendor: u16 = undefined, vendor: u16 = undefined,
pub fn init(bus: u8, slot: u5, function: u3) ?PciDevice { pub fn init(bus: u8, slot: u5, function: u3) ?PciDevice {
var dev = PciDevice{ var dev = PciDevice{ .bus = bus, .slot = slot, .function = function };
.bus = bus, dev.vendor = dev.config_read(u16, 0);
.slot = slot,
.function = function,
};
dev.vendor = dev.config_read_word(0);
if (dev.vendor == 0xffff) return null; if (dev.vendor == 0xffff) return null;
return dev; return dev;
} }
@ -45,7 +43,8 @@ pub const PciDevice = struct {
pub fn format(self: PciDevice) void { pub fn format(self: PciDevice) void {
print("{}:{}.{}", self.bus, self.slot, self.function); 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| if (self.driver()) |d|
print(" {}", d.name); print(" {}", d.name);
println(""); println("");
@ -57,48 +56,44 @@ 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| if (self.vendor != v)
continue; continue;
if (drv.subsystem) |ss| if (self.subsystem() == drv.subsystem.?) if (drv.subsystem) |ss| if (self.subsystem() != ss)
continue; continue;
return drv; return drv;
} }
return null; return null;
} }
// all pci device must implement these
pub fn device(self: PciDevice) u16 { pub fn device(self: PciDevice) u16 {
return self.config_read_word(2); return self.config_read(u16, 0x2);
} }
pub fn subclass(self: PciDevice) u16 { pub fn subclass(self: PciDevice) u8 {
return self.config_read_byte(10); return self.config_read(u8, 0xa);
} }
pub fn class(self: PciDevice) u16 { pub fn class(self: PciDevice) u8 {
return self.config_read_byte(11); return self.config_read(u8, 0xb);
} }
pub fn header_type(self: PciDevice) u16 { pub fn header_type(self: PciDevice) u8 {
return self.config_read_byte(14); return self.config_read(u8, 0xe);
} }
// only for header_type == 0
pub fn subsystem(self: PciDevice) u16 { 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)); arch.outl(PCI_CONFIG_ADDRESS, self.address(offset));
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."),
} }
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));
} }
}; };
@ -114,12 +109,15 @@ const Driver = struct {
const name = "virtio-blk"; const name = "virtio-blk";
pub var Drivers: [1]Driver = [_]Driver{Driver{ .name = &name, .class = 0x1, .subclass = 0x0, .vendor = 0x1af4, .subsystem = 0x2, .init = virtio.init }}; 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 { pub fn scan() void {
var slot: u5 = 0; var slot: u5 = 0;
while (slot < 31) : (slot += 1) { // 0..31
if (PciDevice.init(0, slot, 0)) |device| { while (slot <= std.math.maxInt(u5)) : (slot += 1) {
if (PciDevice.init(0, slot, 0)) |dev| {
var function: u3 = 0; 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 (PciDevice.init(0, slot, function)) |vf| {
if (vf.driver()) |d| d.init(vf); if (vf.driver()) |d| d.init(vf);
} }
@ -130,11 +128,13 @@ 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 (ss) v d drv"); println("b:s.f c,s v d drv");
while (slot < 31) : (slot += 1) { // 0..31
if (PciDevice.init(0, slot, 0)) |device| { while (slot <= std.math.maxInt(u5)) : (slot += 1) {
if (PciDevice.init(0, slot, 0)) |dev| {
var function: u3 = 0; 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 (PciDevice.init(0, slot, function)) |vf| {
vf.format(); vf.format();
} }

View file

@ -69,25 +69,19 @@ const KEYMAP_US = [_][2]u8{
fn ps2_scancode() u8 { fn ps2_scancode() u8 {
var scancode: u8 = 0; var scancode: u8 = 0;
while (true) { while (true) if (x86.inb(PS2_DATA) != scancode) {
if (x86.inb(PS2_DATA) != scancode) {
scancode = x86.inb(PS2_DATA); scancode = x86.inb(PS2_DATA);
if (scancode > 0) if (scancode > 0) return scancode;
return scancode; };
}
}
} }
fn key_isrelease(scancode: u8) bool { fn key_isrelease(scancode: u8) bool {
return (scancode & 1 << 7 != 0); return scancode & (1 << 7) != 0;
} }
pub fn keyboard_handler() void { pub fn keyboard_handler() void {
const scancode = ps2_scancode(); const scancode = ps2_scancode();
const isrelease = key_isrelease(scancode); if (key_isrelease(scancode)) return; // don't process releases
if (isrelease) { const shift = false; // don't know about modifiers yet
return;
}
const shift = false;
console.keypress(KEYMAP_US[scancode][if (shift) 1 else 0]); console.keypress(KEYMAP_US[scancode][if (shift) 1 else 0]);
} }

View file

@ -3,14 +3,16 @@ const mem = @import("std").mem;
const arch = @import("arch/x86/lib/index.zig"); const arch = @import("arch/x86/lib/index.zig");
const std = @import("std"); const std = @import("std");
// VRAM buffer address in physical memory.
pub const VRAM_ADDR = 0xB8000;
pub const VRAM_SIZE = 0x8000;
// Screen size. // Screen size.
pub const VGA_WIDTH = 80; pub const VGA_WIDTH = 80;
pub const VGA_HEIGHT = 25; pub const VGA_HEIGHT = 25;
pub const VGA_SIZE = VGA_WIDTH * VGA_HEIGHT; 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. // Color codes.
pub const Color = enum(u4) { pub const Color = enum(u4) {
@ -39,17 +41,13 @@ pub const VGAEntry = packed struct {
background: Color, background: Color,
}; };
////
// Enable hardware cursor. // Enable hardware cursor.
//
pub fn enableCursor() void { pub fn enableCursor() void {
outb(0x3D4, 0x0A); outb(0x3D4, 0x0A);
outb(0x3D5, 0x00); outb(0x3D5, 0x00);
} }
////
// Disable hardware cursor. // Disable hardware cursor.
//
pub fn disableCursor() void { pub fn disableCursor() void {
outb(0x3D4, 0x0A); outb(0x3D4, 0x0A);
outb(0x3D5, 1 << 5); outb(0x3D5, 1 << 5);
@ -72,33 +70,14 @@ fn printCallback(context: void, string: []const u8) Errors!void {
} }
// VGA status. // VGA status.
pub const VGA = struct { const VGA = struct {
vram: []VGAEntry, vram: []VGAEntry,
cursor: usize, cursor: usize,
foreground: Color, foreground: Color,
background: 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. // Clear the screen.
//
pub fn clear(self: *VGA) void { pub fn clear(self: *VGA) void {
mem.set(VGAEntry, self.vram[0..VGA_SIZE], self.entry(' ')); mem.set(VGAEntry, self.vram[0..VGA_SIZE], self.entry(' '));
@ -131,12 +110,9 @@ pub const VGA = struct {
self.writeChar(' '); self.writeChar(' ');
}, },
// Backspace. // Backspace.
// FIXME: hardcoded 8 here is horrible. '\x08' => {
8 => {
self.cursor -= 1; self.cursor -= 1;
// self.writeChar(' ');
self.vram[self.cursor] = self.entry(' '); self.vram[self.cursor] = self.entry(' ');
// self.cursor -= 1;
}, },
// Any other character. // Any other character.
else => { else => {

21
src/virtio.zig Normal file
View file

@ -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));
}