compiles now, new import architecture
This commit is contained in:
parent
888b51282d
commit
bdc3b2939b
18 changed files with 113 additions and 300 deletions
|
|
@ -7,7 +7,6 @@ pub fn build(b: *Builder) void {
|
||||||
kernel.addPackagePath("x86", "src/arch/x86/index.zig");
|
kernel.addPackagePath("x86", "src/arch/x86/index.zig");
|
||||||
kernel.setOutputDir("build");
|
kernel.setOutputDir("build");
|
||||||
|
|
||||||
// kernel.addAssemblyFile("src/arch/x86/_start.s");
|
|
||||||
kernel.addAssemblyFile("src/arch/x86/gdt.s");
|
kernel.addAssemblyFile("src/arch/x86/gdt.s");
|
||||||
kernel.addAssemblyFile("src/arch/x86/isr.s");
|
kernel.addAssemblyFile("src/arch/x86/isr.s");
|
||||||
kernel.addAssemblyFile("src/arch/x86/paging.s");
|
kernel.addAssemblyFile("src/arch/x86/paging.s");
|
||||||
|
|
|
||||||
2
qemu.sh
2
qemu.sh
|
|
@ -12,8 +12,8 @@ start() {
|
||||||
-m 1337M \
|
-m 1337M \
|
||||||
-curses \
|
-curses \
|
||||||
-append "Hello" \
|
-append "Hello" \
|
||||||
-drive file=disk.img,if=virtio\
|
|
||||||
-kernel ${KERNEL}
|
-kernel ${KERNEL}
|
||||||
|
# -drive file=disk.img,if=virtio\
|
||||||
# -no-reboot \
|
# -no-reboot \
|
||||||
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
# -device virtio-net,netdev=network0 -netdev tap,id=network0,ifname=tap0,script=no,downscript=no \
|
||||||
# build/kernel.iso
|
# build/kernel.iso
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
.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
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
// https://wiki.osdev.org/IDT
|
// https://wiki.osdev.org/IDT
|
||||||
usingnamespace @import("kernel");
|
// usingnamespace @import("kernel");
|
||||||
usingnamespace @import("x86");
|
// usingnamespace @import("x86");
|
||||||
|
usingnamespace @import("index.zig");
|
||||||
|
|
||||||
// Types of gates.
|
// Types of gates.
|
||||||
pub const INTERRUPT_GATE = 0x8E;
|
pub const INTERRUPT_GATE = 0x8E;
|
||||||
pub const SYSCALL_GATE = 0xEE;
|
pub const SYSCALL_GATE = 0xEE;
|
||||||
|
|
||||||
// Interrupt Descriptor Table.
|
// Interrupt Descriptor Table.
|
||||||
var idt: [256]IDTEntry = undefined;
|
var idt_table: [256]IDTEntry = undefined;
|
||||||
|
|
||||||
// IDT descriptor register pointing at the IDT.
|
// IDT descriptor register pointing at the IDT.
|
||||||
const idtr = IDTRegister{
|
const idtr = IDTRegister{
|
||||||
.limit = u16(@sizeOf(@typeOf(idt))),
|
.limit = u16(@sizeOf(@typeOf(idt_table))),
|
||||||
.base = &idt,
|
.base = &idt_table,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Structure representing an entry in the IDT.
|
// Structure representing an entry in the IDT.
|
||||||
|
|
@ -40,11 +41,11 @@ const IDTRegister = packed struct {
|
||||||
pub fn setGate(n: u8, flags: u8, offset: extern fn () void) void {
|
pub fn setGate(n: u8, flags: u8, offset: extern fn () void) void {
|
||||||
const intOffset = @ptrToInt(offset);
|
const intOffset = @ptrToInt(offset);
|
||||||
|
|
||||||
idt[n].offset_low = @truncate(u16, intOffset);
|
idt_table[n].offset_low = @truncate(u16, intOffset);
|
||||||
idt[n].offset_high = @truncate(u16, intOffset >> 16);
|
idt_table[n].offset_high = @truncate(u16, intOffset >> 16);
|
||||||
idt[n].flags = flags;
|
idt_table[n].flags = flags;
|
||||||
idt[n].zero = 0;
|
idt_table[n].zero = 0;
|
||||||
idt[n].selector = gdt.KERNEL_CODE;
|
idt_table[n].selector = gdt.KERNEL_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the Interrupt Descriptor Table.
|
// Initialize the Interrupt Descriptor Table.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
usingnamespace @import("lib/io.zig");
|
pub usingnamespace @import("../../vga.zig");
|
||||||
usingnamespace @import("lib/instructions.zig");
|
pub const multiboot = @import("../../multiboot.zig");
|
||||||
usingnamespace @import("main.zig");
|
|
||||||
|
|
||||||
const memory = @import("memory.zig");
|
pub usingnamespace @import("lib/io.zig");
|
||||||
const paging = @import("paging.zig");
|
pub usingnamespace @import("lib/instructions.zig");
|
||||||
const idt = @import("idt.zig");
|
pub usingnamespace @import("main.zig");
|
||||||
const gdt = @import("gdt.zig");
|
|
||||||
const interrupt = @import("interrupt.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;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("index.zig");
|
||||||
const x86 = @import("x86");
|
// const x86 = @import("index.zig");
|
||||||
const isr = @import("isr.zig");
|
// const isr = @import("isr.zig");
|
||||||
|
|
||||||
// PIC ports.
|
// PIC ports.
|
||||||
const PIC1_CMD = 0x20;
|
const PIC1_CMD = 0x20;
|
||||||
|
|
@ -32,16 +32,17 @@ var handlers = [_]fn () void{unhandled} ** 48;
|
||||||
|
|
||||||
fn unhandled() noreturn {
|
fn unhandled() noreturn {
|
||||||
const n = isr.context.interrupt_n;
|
const n = isr.context.interrupt_n;
|
||||||
|
print("unhandled interrupt number {d}", n);
|
||||||
if (n < IRQ_0) {
|
if (n < IRQ_0) {
|
||||||
println("unhandled exception number {d}", n);
|
println(" (exception)");
|
||||||
} else {
|
} else {
|
||||||
println("unhandled IRQ number {d} (intr {d})", n - IRQ_0, n);
|
println(" (IRQ number {d})", n - IRQ_0);
|
||||||
}
|
}
|
||||||
x86.hang();
|
hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn picwait() void {
|
inline fn picwait() void {
|
||||||
x86.outb(WAIT_PORT, 0);
|
outb(WAIT_PORT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
@ -81,8 +82,8 @@ export fn interruptDispatch() void {
|
||||||
|
|
||||||
// If no user thread is ready to run, halt here and wait for interrupts.
|
// If no user thread is ready to run, halt here and wait for interrupts.
|
||||||
// if (scheduler.current() == null) {
|
// if (scheduler.current() == null) {
|
||||||
// x86.sti();
|
// sti();
|
||||||
// x86.hlt();
|
// hlt();
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,8 +93,8 @@ inline fn spuriousIRQ(irq: u8) bool {
|
||||||
// TODO: handle spurious IRQ15.
|
// TODO: handle spurious IRQ15.
|
||||||
|
|
||||||
// Read the value of the In-Service Register.
|
// Read the value of the In-Service Register.
|
||||||
x86.outb(PIC1_CMD, ISR_READ);
|
outb(PIC1_CMD, ISR_READ);
|
||||||
const in_service = x86.inb(PIC1_CMD);
|
const in_service = inb(PIC1_CMD);
|
||||||
|
|
||||||
// Verify whether IRQ7 is set in the ISR.
|
// Verify whether IRQ7 is set in the ISR.
|
||||||
return (in_service & (1 << 7)) == 0;
|
return (in_service & (1 << 7)) == 0;
|
||||||
|
|
@ -103,11 +104,11 @@ inline fn startOfInterrupt(irq: u8) void {
|
||||||
// mask the irq and then ACK
|
// mask the irq and then ACK
|
||||||
if (irq >= 8) {
|
if (irq >= 8) {
|
||||||
maskIRQ(irq, true);
|
maskIRQ(irq, true);
|
||||||
x86.outb(PIC1_CMD, ACK);
|
outb(PIC1_CMD, ACK);
|
||||||
x86.outb(PIC2_CMD, ACK);
|
outb(PIC2_CMD, ACK);
|
||||||
} else {
|
} else {
|
||||||
maskIRQ(irq, true);
|
maskIRQ(irq, true);
|
||||||
x86.outb(PIC1_CMD, ACK);
|
outb(PIC1_CMD, ACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,10 +116,10 @@ inline fn endOfInterrupt(irq: u8) void {
|
||||||
// unmask the irq and then ACK
|
// unmask the irq and then ACK
|
||||||
if (irq >= 8) {
|
if (irq >= 8) {
|
||||||
maskIRQ(irq, false);
|
maskIRQ(irq, false);
|
||||||
x86.outb(PIC2_CMD, ACK);
|
outb(PIC2_CMD, ACK);
|
||||||
} else {
|
} else {
|
||||||
maskIRQ(irq, false);
|
maskIRQ(irq, false);
|
||||||
x86.outb(PIC1_CMD, ACK);
|
outb(PIC1_CMD, ACK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,33 +134,33 @@ pub fn registerIRQ(irq: u8, handler: fn () void) void {
|
||||||
|
|
||||||
fn remapPIC() void {
|
fn remapPIC() void {
|
||||||
// ICW1: start initialization sequence.
|
// ICW1: start initialization sequence.
|
||||||
x86.outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
||||||
picwait();
|
picwait();
|
||||||
x86.outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
||||||
picwait();
|
picwait();
|
||||||
|
|
||||||
// ICW2: Interrupt Vector offsets of IRQs.
|
// ICW2: Interrupt Vector offsets of IRQs.
|
||||||
x86.outb(PIC1_DATA, IRQ_0); // IRQ 0..7 -> Interrupt 32..39
|
outb(PIC1_DATA, IRQ_0); // IRQ 0..7 -> Interrupt 32..39
|
||||||
picwait();
|
picwait();
|
||||||
x86.outb(PIC2_DATA, IRQ_0 + 8); // IRQ 8..15 -> Interrupt 40..47
|
outb(PIC2_DATA, IRQ_0 + 8); // IRQ 8..15 -> Interrupt 40..47
|
||||||
picwait();
|
picwait();
|
||||||
|
|
||||||
// ICW3: IRQ line 2 to connect master to slave PIC.
|
// ICW3: IRQ line 2 to connect master to slave PIC.
|
||||||
x86.outb(PIC1_DATA, 1 << 2);
|
outb(PIC1_DATA, 1 << 2);
|
||||||
picwait();
|
picwait();
|
||||||
x86.outb(PIC2_DATA, 2);
|
outb(PIC2_DATA, 2);
|
||||||
picwait();
|
picwait();
|
||||||
|
|
||||||
// ICW4: 80x86 mode.
|
// ICW4: 80x86 mode.
|
||||||
x86.outb(PIC1_DATA, ICW4_8086);
|
outb(PIC1_DATA, ICW4_8086);
|
||||||
picwait();
|
picwait();
|
||||||
x86.outb(PIC2_DATA, ICW4_8086);
|
outb(PIC2_DATA, ICW4_8086);
|
||||||
picwait();
|
picwait();
|
||||||
|
|
||||||
// Mask all IRQs.
|
// Mask all IRQs.
|
||||||
x86.outb(PIC1_DATA, 0xFF);
|
outb(PIC1_DATA, 0xFF);
|
||||||
picwait();
|
picwait();
|
||||||
x86.outb(PIC2_DATA, 0xFF);
|
outb(PIC2_DATA, 0xFF);
|
||||||
picwait();
|
picwait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,16 +168,16 @@ 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.
|
// 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 = inb(port); // Retrieve the current mask.
|
||||||
|
|
||||||
// Mask or unmask the interrupt.
|
// Mask or unmask the interrupt.
|
||||||
const shift = @intCast(u3, irq % 8);
|
const shift = @intCast(u3, irq % 8);
|
||||||
if (mask) {
|
if (mask) {
|
||||||
x86.outb(port, old | (u8(1) << shift));
|
outb(port, old | (u8(1) << shift));
|
||||||
} else {
|
} else {
|
||||||
x86.outb(port, old & ~(u8(1) << shift));
|
outb(port, old & ~(u8(1) << shift));
|
||||||
}
|
}
|
||||||
const new = x86.inb(port); // Retrieve the current mask.
|
const new = inb(port); // Retrieve the current mask.
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
usingnamespace @import("x86");
|
usingnamespace @import("index.zig");
|
||||||
|
|
||||||
// Interrupt Service Routines defined externally in assembly.
|
// Interrupt Service Routines defined externally in assembly.
|
||||||
extern fn isr0() void;
|
extern fn isr0() void;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
usingnamespace @import("kernel");
|
// usingnamespace @import("kernel");
|
||||||
usingnamespace @import("x86");
|
usingnamespace @import("index.zig");
|
||||||
|
// const multiboot = @import("../../multiboot.zig");
|
||||||
|
|
||||||
/// x86 specific intialization
|
/// x86 specific intialization
|
||||||
pub fn x86_main(info: *const MultibootInfo) void {
|
pub fn x86_main(info: *const multiboot.MultibootInfo) void {
|
||||||
gdt.initialize();
|
gdt.initialize();
|
||||||
idt.initialize();
|
idt.initialize();
|
||||||
memory.initialize(info);
|
memory.initialize(info);
|
||||||
paging.initialize();
|
paging.initialize();
|
||||||
|
|
||||||
// enable interrupts
|
// enable interrupts
|
||||||
x86.sti();
|
sti();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("index.zig");
|
||||||
|
|
||||||
var stack: [*]usize = undefined; // Stack of free physical page.
|
var stack: [*]usize = undefined; // Stack of free physical page.
|
||||||
var stack_index: usize = 0; // Index into the stack.
|
var stack_index: usize = 0; // Index into the stack.
|
||||||
|
|
@ -51,10 +51,10 @@ pub fn free(address: usize) void {
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// info: Information structure from bootloader.
|
// info: Information structure from bootloader.
|
||||||
//
|
//
|
||||||
pub fn initialize(info: *const MultibootInfo) void {
|
pub fn initialize(info: *const multiboot.MultibootInfo) void {
|
||||||
// Ensure the bootloader has given us the memory map.
|
// Ensure the bootloader has given us the memory map.
|
||||||
assert((info.flags & MULTIBOOT_INFO_MEMORY) != 0);
|
assert((info.flags & multiboot.MULTIBOOT_INFO_MEMORY) != 0);
|
||||||
assert((info.flags & MULTIBOOT_INFO_MEM_MAP) != 0);
|
assert((info.flags & multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
|
||||||
|
|
||||||
// Place the stack of free pages after the last Multiboot module.
|
// Place the stack of free pages after the last Multiboot module.
|
||||||
stack = @intToPtr([*]usize, 0x200000);
|
stack = @intToPtr([*]usize, 0x200000);
|
||||||
|
|
@ -65,7 +65,7 @@ pub fn initialize(info: *const MultibootInfo) void {
|
||||||
|
|
||||||
var map: usize = info.mmap_addr;
|
var map: usize = info.mmap_addr;
|
||||||
while (map < info.mmap_addr + info.mmap_length) {
|
while (map < info.mmap_addr + info.mmap_length) {
|
||||||
var entry = @intToPtr(*MultibootMMapEntry, map);
|
var entry = @intToPtr(*multiboot.MultibootMMapEntry, map);
|
||||||
|
|
||||||
// Calculate the start and end of this memory area.
|
// Calculate the start and end of this memory area.
|
||||||
var start = @truncate(usize, entry.addr);
|
var start = @truncate(usize, entry.addr);
|
||||||
|
|
@ -74,7 +74,7 @@ pub fn initialize(info: *const MultibootInfo) void {
|
||||||
start = if (start >= stack_end) start else stack_end;
|
start = if (start >= stack_end) start else stack_end;
|
||||||
|
|
||||||
// Flag all the pages in this memory area as free.
|
// Flag all the pages in this memory area as free.
|
||||||
if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
|
if (entry.type == multiboot.MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE)
|
||||||
free(start);
|
free(start);
|
||||||
|
|
||||||
// Go to the next entry in the memory map.
|
// Go to the next entry in the memory map.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("index.zig");
|
||||||
usingnamespace @import("x86");
|
// usingnamespace @import("x86");
|
||||||
|
|
||||||
extern fn setupPaging(phys_pd: usize) void;
|
extern fn setupPaging(phys_pd: usize) void;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("index.zig");
|
||||||
|
|
||||||
var command: [10]u8 = undefined;
|
var command: [10]u8 = undefined;
|
||||||
var command_len: usize = 0;
|
var command_len: usize = 0;
|
||||||
|
|
@ -30,6 +30,6 @@ pub fn keypress(char: u8) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize() void {
|
pub fn initialize() void {
|
||||||
@import("x86").interrupt.registerIRQ(1, ps2.keyboard_handler);
|
x86.interrupt.registerIRQ(1, ps2.keyboard_handler);
|
||||||
print("> ");
|
print("> ");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
pub const assert = @import("std").debug.assert;
|
||||||
|
pub const std = @import("std");
|
||||||
|
|
||||||
pub usingnamespace @import("vga.zig");
|
pub usingnamespace @import("vga.zig");
|
||||||
pub const main = @import("main.zig");
|
|
||||||
pub const multiboot = @import("multiboot.zig");
|
pub const multiboot = @import("multiboot.zig");
|
||||||
pub const console = @import("console.zig");
|
pub const console = @import("console.zig");
|
||||||
pub const pci = @import("pci.zig");
|
pub const pci = @import("pci/pci.zig");
|
||||||
pub const ps2 = @import("ps2.zig");
|
pub const ps2 = @import("ps2.zig");
|
||||||
|
pub const x86 = @import("arch/x86/index.zig");
|
||||||
pub const assert = @import("std").debug.assert;
|
|
||||||
|
|
|
||||||
32
src/main.zig
32
src/main.zig
|
|
@ -1,29 +1,43 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("kernel");
|
||||||
|
// const x86 = @import("x86");
|
||||||
|
|
||||||
const x86 = @import("x86");
|
// Place the header at the very beginning of the binary.
|
||||||
|
export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
|
||||||
|
const MAGIC = u32(0x1BADB002); // multiboot magic
|
||||||
|
const ALIGN = u32(1 << 0); // Align loaded modules at 4k
|
||||||
|
const MEMINFO = u32(1 << 1); // Receive a memory map from the bootloader.
|
||||||
|
const ADDR = u32(1 << 16); // Load specific addr
|
||||||
|
const FLAGS = ALIGN | MEMINFO; // Combine the flags.
|
||||||
|
|
||||||
|
break :multiboot multiboot.MultibootHeader{
|
||||||
|
.magic = MAGIC,
|
||||||
|
.flags = FLAGS,
|
||||||
|
.checksum = ~(MAGIC +% FLAGS) +% 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined;
|
export var stack_bytes: [16 * 1024]u8 align(16) linksection(".bss") = undefined;
|
||||||
const stack_bytes_slice = stack_bytes[0..];
|
const stack_bytes_slice = stack_bytes[0..];
|
||||||
|
|
||||||
// linker.ld entrypoint
|
// linker.ld entrypoint
|
||||||
export nakedcc fn _start() noreturn {
|
export nakedcc fn __start() noreturn {
|
||||||
// ebx -> multiboot info
|
|
||||||
const info: u32 = asm volatile (""
|
|
||||||
: [result] "={ebx}" (-> u32)
|
|
||||||
);
|
|
||||||
// eax -> multiboot magic
|
// eax -> multiboot magic
|
||||||
const magic: u32 = asm volatile (""
|
const magic: u32 = asm volatile (""
|
||||||
: [result] "={eax}" (-> u32)
|
: [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, magic, @intToPtr(*const multiboot.MultibootInfo, info));
|
||||||
while (true) {}
|
// @newStackCall(stack_bytes_slice, kmain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// arch independant initialization
|
// arch independant initialization
|
||||||
fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn {
|
||||||
assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC);
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
println("--- {x} ---", magic);
|
||||||
|
// assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC);
|
||||||
println("--- x86 initialization ---");
|
println("--- x86 initialization ---");
|
||||||
x86.x86_main(info);
|
x86.x86_main(info);
|
||||||
println("--- core initialization ---");
|
println("--- core initialization ---");
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ pub const MultibootModule = packed struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Multiboot structure to be read by the bootloader.
|
// Multiboot structure to be read by the bootloader.
|
||||||
const MultibootHeader = packed struct {
|
pub const MultibootHeader = packed struct {
|
||||||
magic: u32, // Must be equal to header magic number.
|
magic: u32, // Must be equal to header magic number.
|
||||||
flags: u32, // Feature flags.
|
flags: u32, // Feature flags.
|
||||||
checksum: u32, // Above fields plus this one must equal 0 mod 2^32.
|
checksum: u32, // Above fields plus this one must equal 0 mod 2^32.
|
||||||
|
|
@ -136,18 +136,3 @@ const MultibootHeader = packed struct {
|
||||||
entry_addr: u32 = 0,
|
entry_addr: u32 = 0,
|
||||||
};
|
};
|
||||||
// NOTE: this structure is incomplete.
|
// NOTE: this structure is incomplete.
|
||||||
|
|
||||||
// Place the header at the very beginning of the binary.
|
|
||||||
export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
|
|
||||||
const MAGIC = u32(0x1BADB002); // multiboot magic
|
|
||||||
const ALIGN = u32(1 << 0); // Align loaded modules at 4k
|
|
||||||
const MEMINFO = u32(1 << 1); // Receive a memory map from the bootloader.
|
|
||||||
const ADDR = u32(1 << 16); // Load specific addr
|
|
||||||
const FLAGS = ALIGN | MEMINFO; // Combine the flags.
|
|
||||||
|
|
||||||
break :multiboot MultibootHeader{
|
|
||||||
.magic = MAGIC,
|
|
||||||
.flags = FLAGS,
|
|
||||||
.checksum = ~(MAGIC +% FLAGS) +% 1,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
||||||
157
src/pci.zig
157
src/pci.zig
|
|
@ -1,157 +0,0 @@
|
||||||
usingnamespace @import("kernel");
|
|
||||||
const arch = @import("x86");
|
|
||||||
const std = @import("std");
|
|
||||||
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();
|
|
||||||
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(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
|
|
||||||
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."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 <= std.math.maxInt(u5)) : (slot += 1) {
|
|
||||||
if (PciDevice.init(0, slot, 0)) |dev| {
|
|
||||||
var function: u3 = 0;
|
|
||||||
// 0..7
|
|
||||||
while (function <= std.math.maxInt(u3)) : (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");
|
|
||||||
// 0..31
|
|
||||||
while (slot <= std.math.maxInt(u5)) : (slot += 1) {
|
|
||||||
if (PciDevice.init(0, slot, 0)) |dev| {
|
|
||||||
var function: u3 = 0;
|
|
||||||
// 0..7
|
|
||||||
while (function <= std.math.maxInt(u3)) : (function += 1) {
|
|
||||||
if (PciDevice.init(0, slot, function)) |vf| {
|
|
||||||
vf.format();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
usingnamespace @import("kernel");
|
usingnamespace @import("index.zig");
|
||||||
const x86 = @import("x86");
|
// const x86 = @import("x86");
|
||||||
|
|
||||||
const PS2_DATA = 0x60;
|
const PS2_DATA = 0x60;
|
||||||
const PS2_STATUS = 0x64;
|
const PS2_STATUS = 0x64;
|
||||||
|
|
|
||||||
18
src/vga.zig
18
src/vga.zig
|
|
@ -1,4 +1,4 @@
|
||||||
const arch = @import("x86");
|
const x86 = @import("arch/x86/index.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
// Screen size.
|
// Screen size.
|
||||||
|
|
@ -156,10 +156,10 @@ const VGA = struct {
|
||||||
// Use the software cursor as the source of truth.
|
// Use the software cursor as the source of truth.
|
||||||
//
|
//
|
||||||
pub fn updateCursor(self: *const VGA) void {
|
pub fn updateCursor(self: *const VGA) void {
|
||||||
arch.outb(0x3D4, 0x0F);
|
x86.outb(0x3D4, 0x0F);
|
||||||
arch.outb(0x3D5, @truncate(u8, self.cursor));
|
x86.outb(0x3D5, @truncate(u8, self.cursor));
|
||||||
arch.outb(0x3D4, 0x0E);
|
x86.outb(0x3D4, 0x0E);
|
||||||
arch.outb(0x3D5, @truncate(u8, self.cursor >> 8));
|
x86.outb(0x3D5, @truncate(u8, self.cursor >> 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
@ -169,11 +169,11 @@ const VGA = struct {
|
||||||
pub fn fetchCursor(self: *VGA) void {
|
pub fn fetchCursor(self: *VGA) void {
|
||||||
var cursor: usize = 0;
|
var cursor: usize = 0;
|
||||||
|
|
||||||
arch.outb(0x3D4, 0x0E);
|
x86.outb(0x3D4, 0x0E);
|
||||||
cursor |= usize(arch.inb(0x3D5)) << 8;
|
cursor |= usize(x86.inb(0x3D5)) << 8;
|
||||||
|
|
||||||
arch.outb(0x3D4, 0x0F);
|
x86.outb(0x3D4, 0x0F);
|
||||||
cursor |= arch.inb(0x3D5);
|
cursor |= x86.inb(0x3D5);
|
||||||
|
|
||||||
self.cursor = cursor;
|
self.cursor = cursor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
usingnamespace @import("kernel");
|
|
||||||
|
|
||||||
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("dev features =0x{x}", pci.config_read(u32, 0x10));
|
|
||||||
println("guest features=0x{x}", pci.config_read(u32, 0x14));
|
|
||||||
println("queue addr =0x{x}", pci.config_read(u32, 0x18));
|
|
||||||
println("queue size =0x{x}", pci.config_read(u16, 0x1c));
|
|
||||||
println("queue select =0x{x}", pci.config_read(u16, 0x1e));
|
|
||||||
println("queue notify =0x{x}", pci.config_read(u16, 0x20));
|
|
||||||
println("device status =0x{x}", pci.config_read(u8, 0x22));
|
|
||||||
println("isr status =0x{x}", pci.config_read(u8, 0x23));
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue