added virtio, refactoring untill compiler is fixed
This commit is contained in:
parent
4c9f4b54d8
commit
d051e1b0c8
12 changed files with 112 additions and 163 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ pub fn allocate() ?usize {
|
|||
println("out of memory");
|
||||
return null;
|
||||
}
|
||||
|
||||
stack_index -= 1;
|
||||
return stack[stack_index];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
10
src/main.zig
10
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");
|
||||
}
|
||||
|
|
|
|||
80
src/pci.zig
80
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();
|
||||
}
|
||||
|
|
|
|||
20
src/ps2.zig
20
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]);
|
||||
}
|
||||
|
|
|
|||
40
src/vga.zig
40
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 => {
|
||||
|
|
|
|||
21
src/virtio.zig
Normal file
21
src/virtio.zig
Normal 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));
|
||||
}
|
||||
Loading…
Reference in a new issue