towards 0.10.1

This commit is contained in:
Jack Halford 2023-08-06 15:38:23 +02:00
parent e392799b91
commit 08d447115d
No known key found for this signature in database
GPG key ID: A427D956E8E67679
17 changed files with 239 additions and 205 deletions

View file

@ -1,4 +1,7 @@
const Builder = @import("std").build.Builder; const Builder = @import("std").build.Builder;
const Target = @import("std").Target;
const CrossTarget = @import("std").zig.CrossTarget;
const Feature = @import("std").Target.Cpu.Feature;
const builtin = @import("builtin"); const builtin = @import("builtin");
const std = @import("std"); const std = @import("std");
@ -6,6 +9,7 @@ pub fn build(b: *Builder) void {
const kernel = b.addExecutable("kernel", "src/main.zig"); const kernel = b.addExecutable("kernel", "src/main.zig");
kernel.addPackagePath("kernel", "src/index.zig"); kernel.addPackagePath("kernel", "src/index.zig");
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/start.s");
@ -14,18 +18,28 @@ pub fn build(b: *Builder) void {
kernel.addAssemblyFile("src/arch/x86/paging.s"); kernel.addAssemblyFile("src/arch/x86/paging.s");
kernel.addAssemblyFile("src/arch/x86/switch_tasks.s"); kernel.addAssemblyFile("src/arch/x86/switch_tasks.s");
// const features = Target.x86.Feature;
// var disabled_features = Feature.Set.empty;
// var enabled_features = Feature.Set.empty;
// disabled_features.addFeature(@enumToInt(features.mmx));
// disabled_features.addFeature(@enumToInt(features.sse));
// disabled_features.addFeature(@enumToInt(features.sse2));
// disabled_features.addFeature(@enumToInt(features.avx));
// disabled_features.addFeature(@enumToInt(features.avx2));
// enabled_features.addFeature(@enumToInt(features.soft_float));
const target = CrossTarget{
.cpu_arch = Target.Cpu.Arch.i386,
.os_tag = Target.Os.Tag.freestanding,
.abi = Target.Abi.none,
// .cpu_features_sub = disabled_features,
// .cpu_features_add = enabled_features
};
kernel.setTarget(target);
kernel.setBuildMode(b.standardReleaseOptions()); kernel.setBuildMode(b.standardReleaseOptions());
kernel.setTheTarget(std.Target{ kernel.setLinkerScriptPath(.{ .path = "src/arch/x86/linker.ld" });
.Cross = std.Target.Cross{
.arch = std.Target.Arch.i386,
.os = std.Target.Os.freestanding,
.abi = std.Target.Abi.none,
.cpu_features = std.Target.CpuFeatures.initFromCpu(
builtin.Arch.i386,
&builtin.Target.x86.cpu._i686,
),
},
});
kernel.setLinkerScriptPath("src/arch/x86/linker.ld");
b.default_step.dependOn(&kernel.step); b.default_step.dependOn(&kernel.step);
} }

View file

@ -1,7 +1,7 @@
// https://wiki.osdev.org/IDT // https://wiki.osdev.org/IDT
// usingnamespace @import("kernel");
// usingnamespace @import("x86"); const kernel = @import("kernel");
usingnamespace @import("index.zig"); const x86 = @import("x86");
// Types of gates. // Types of gates.
pub const INTERRUPT_GATE = 0x8E; pub const INTERRUPT_GATE = 0x8E;
@ -38,51 +38,52 @@ const IDTRegister = packed struct {
// flags: Type and attributes. // flags: Type and attributes.
// offset: Address of the ISR. // offset: Address of the ISR.
// //
pub fn setGate(n: u8, flags: u8, offset: extern fn () void) void { pub fn setGate(n: u8, flags: u8, offset: anytype) void {
const intOffset = @ptrToInt(offset); const intOffset = @ptrToInt(&offset);
// const intOffset = offset;
idt_table[n].offset_low = @truncate(u16, intOffset); idt_table[n].offset_low = @truncate(u16, intOffset);
idt_table[n].offset_high = @truncate(u16, intOffset >> 16); idt_table[n].offset_high = @truncate(u16, intOffset >> 16);
idt_table[n].flags = flags; idt_table[n].flags = flags;
idt_table[n].zero = 0; idt_table[n].zero = 0;
idt_table[n].selector = gdt.KERNEL_CODE; idt_table[n].selector = x86.gdt.KERNEL_CODE;
} }
// Initialize the Interrupt Descriptor Table. // Initialize the Interrupt Descriptor Table.
pub fn initialize() void { pub fn initialize() void {
// configure PIC // configure PIC
interrupt.remapPIC(); x86.interrupt.remapPIC();
interrupt.configPIT(); x86.interrupt.configPIT();
// install ISRs // install ISRs
isr.install_exceptions(); x86.isr.install_exceptions();
isr.install_irqs(); x86.isr.install_irqs();
isr.install_syscalls(); x86.isr.install_syscalls();
interrupt.registerIRQ(0, kernel.time.increment); x86.interrupt.registerIRQ(0, kernel.time.increment);
interrupt.registerIRQ(1, kernel.ps2.keyboard_handler); x86.interrupt.registerIRQ(1, kernel.ps2.keyboard_handler);
interrupt.register(1, debug_trap); x86.interrupt.register(1, debug_trap);
interrupt.register(13, general_protection_fault); x86.interrupt.register(13, general_protection_fault);
interrupt.register(14, page_fault); x86.interrupt.register(14, page_fault);
// load IDT // load IDT
lidt(@ptrToInt(&idtr)); x86.instr.lidt(@ptrToInt(&idtr));
} }
fn general_protection_fault() void { fn general_protection_fault() void {
kernel.println("general protection fault", .{}); kernel.println("general protection fault", .{});
hang(); x86.instr.hang();
} }
fn debug_trap() void { fn debug_trap() void {
kernel.println("debug fault/trap", .{}); kernel.println("debug fault/trap", .{});
kernel.println("dr7: 0b{b}", .{dr7()}); kernel.println("dr7: 0b{b}", .{x86.instr.dr7()});
} }
fn page_fault() void { fn page_fault() void {
const vaddr = cr2(); const vaddr = x86.instr.cr2();
kernel.println("cr2: 0x{x}", .{vaddr}); kernel.println("cr2: 0x{x}", .{vaddr});
kernel.println("phy: 0x{x}", .{paging.translate(vaddr)}); kernel.println("phy: 0x{x}", .{kernel.paging.translate(vaddr)});
kernel.println("pde: 0x{x} ({})", .{ paging.pde(vaddr), vaddr >> 22 }); kernel.println("pde: 0x{x} ({})", .{ kernel.paging.pde(vaddr), vaddr >> 22 });
kernel.println("pte: 0x{x} ({})", .{ paging.pte(vaddr), vaddr >> 12 }); kernel.println("pte: 0x{x} ({})", .{ kernel.paging.pte(vaddr), vaddr >> 12 });
// paging.format(); // paging.format();
hang(); x86.instr.hang();
} }

View file

@ -5,8 +5,8 @@ pub const kernel = @import("../../index.zig");
// x86 namespace // x86 namespace
pub const PAGE_SIZE: usize = 4096; pub const PAGE_SIZE: usize = 4096;
pub usingnamespace @import("lib/io.zig"); pub const io = @import("lib/io.zig");
pub usingnamespace @import("lib/instructions.zig"); pub const instr = @import("lib/instructions.zig");
pub usingnamespace @import("main.zig"); pub usingnamespace @import("main.zig");
pub const pmem = @import("pmem.zig"); pub const pmem = @import("pmem.zig");
pub const paging = @import("paging.zig"); pub const paging = @import("paging.zig");

View file

@ -1,4 +1,6 @@
usingnamespace @import("index.zig"); const std = @import("std");
const kernel = @import("kernel");
const x86 = @import("x86");
// PIC ports. // PIC ports.
const PIC1_CMD = 0x20; const PIC1_CMD = 0x20;
@ -28,37 +30,37 @@ const IRQ_15 = IRQ_0 + 15;
// Interrupt Vector offsets of syscalls. // Interrupt Vector offsets of syscalls.
const SYSCALL = 128; const SYSCALL = 128;
// Registered interrupt handlers. (see isr.s) // Registered interrupt handlers. (see x86.isr.s)
var handlers = [_]fn () void{unhandled} ** 48; var handlers = [_]fn () void{unhandled} ** 48;
// Registered IRQ subscribers. (see isr.s) // Registered IRQ subscribers. (see x86.isr.s)
// var irq_subscribers = []MailboxId{MailboxId.Kernel} ** 16; // var irq_subscribers = []MailboxId{MailboxId.Kernel} ** 16;
fn unhandled() noreturn { fn unhandled() noreturn {
const n = isr.context.interrupt_n; const n = x86.isr.context.interrupt_n;
kernel.print("unhandled interrupt number {d}", .{n}); kernel.vga.print("unhandled interrupt number {d}", .{n});
if (n < IRQ_0) kernel.println(" (exception)", .{}); if (n < IRQ_0) kernel.vga.println(" (exception)", .{});
if (n >= IRQ_0) kernel.println(" (IRQ number {d})", .{n - IRQ_0}); if (n >= IRQ_0) kernel.vga.println(" (IRQ number {d})", .{n - IRQ_0});
hang(); x86.instr.hang();
} }
inline fn picwait() void { inline fn picwait() void {
outb(WAIT_PORT, 0); x86.io.outb(WAIT_PORT, 0);
} }
//// ////
// Call the correct handler based on the interrupt number. // Call the correct handler based on the interrupt number.
// //
export fn interruptDispatch() void { export fn interruptDispatch() void {
const n = @intCast(u8, isr.context.interrupt_n); const n = @intCast(u8, x86.isr.context.interrupt_n);
switch (n) { switch (n) {
// Exceptions. // Exceptions.
EXCEPTION_0...EXCEPTION_31 => { EXCEPTION_0...EXCEPTION_31 => {
kernel.println("", .{}); kernel.vga.println("", .{});
kernel.println("num: {}", .{n}); kernel.vga.println("num: {}", .{n});
kernel.println("err: {}", .{@truncate(u8, isr.context.error_code)}); kernel.vga.println("err: {}", .{@truncate(u8, x86.isr.context.error_code)});
kernel.println("ip: 0x{x}", .{@truncate(u16, isr.context.eip)}); kernel.vga.println("ip: 0x{x}", .{@truncate(u16, x86.isr.context.eip)});
kernel.println("ip: 0x{x}", .{@truncate(u16, isr.context.eip >> 16)}); kernel.vga.println("ip: 0x{x}", .{@truncate(u16, x86.isr.context.eip >> 16)});
return handlers[n](); return handlers[n]();
}, },
@ -74,7 +76,7 @@ export fn interruptDispatch() void {
// Syscalls. // Syscalls.
// SYSCALL => { // SYSCALL => {
// const syscall_n = isr.context.registers.eax; // const syscall_n = x86.isr.context.registers.eax;
// if (syscall_n < syscall.handlers.len) { // if (syscall_n < syscall.handlers.len) {
// syscall.handlers[syscall_n](); // syscall.handlers[syscall_n]();
// } else { // } else {
@ -98,8 +100,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.
outb(PIC1_CMD, ISR_READ); x86.io.outb(PIC1_CMD, ISR_READ);
const in_service = inb(PIC1_CMD); const in_service = x86.io.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;
@ -109,11 +111,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);
outb(PIC1_CMD, ACK); x86.io.outb(PIC1_CMD, ACK);
outb(PIC2_CMD, ACK); x86.io.outb(PIC2_CMD, ACK);
} else { } else {
maskIRQ(irq, true); maskIRQ(irq, true);
outb(PIC1_CMD, ACK); x86.io.outb(PIC1_CMD, ACK);
} }
} }
@ -121,10 +123,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);
outb(PIC2_CMD, ACK); x86.io.outb(PIC2_CMD, ACK);
} else { } else {
maskIRQ(irq, false); maskIRQ(irq, false);
outb(PIC1_CMD, ACK); x86.io.outb(PIC1_CMD, ACK);
} }
} }
@ -139,33 +141,33 @@ pub fn registerIRQ(irq: u8, handler: fn () void) void {
pub fn remapPIC() void { pub fn remapPIC() void {
// ICW1: start initialization sequence. // ICW1: start initialization sequence.
outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4); x86.io.outb(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
picwait(); picwait();
outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4); x86.io.outb(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
picwait(); picwait();
// ICW2: Interrupt Vector offsets of IRQs. // ICW2: Interrupt Vector offsets of IRQs.
outb(PIC1_DATA, IRQ_0); // IRQ 0..7 -> Interrupt 32..39 x86.io.outb(PIC1_DATA, IRQ_0); // IRQ 0..7 -> Interrupt 32..39
picwait(); picwait();
outb(PIC2_DATA, IRQ_0 + 8); // IRQ 8..15 -> Interrupt 40..47 x86.io.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.
outb(PIC1_DATA, 1 << 2); x86.io.outb(PIC1_DATA, 1 << 2);
picwait(); picwait();
outb(PIC2_DATA, 2); x86.io.outb(PIC2_DATA, 2);
picwait(); picwait();
// ICW4: 80x86 mode. // ICW4: 80x86 mode.
outb(PIC1_DATA, ICW4_8086); x86.io.outb(PIC1_DATA, ICW4_8086);
picwait(); picwait();
outb(PIC2_DATA, ICW4_8086); x86.io.outb(PIC2_DATA, ICW4_8086);
picwait(); picwait();
// Mask all IRQs. // Mask all IRQs.
outb(PIC1_DATA, 0xFF); x86.io.outb(PIC1_DATA, 0xFF);
picwait(); picwait();
outb(PIC2_DATA, 0xFF); x86.io.outb(PIC2_DATA, 0xFF);
picwait(); picwait();
} }
@ -173,15 +175,16 @@ pub fn maskIRQ(irq: u8, comptime 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 = @as(u16, if (irq < 8) PIC1_DATA else PIC2_DATA); const port = @as(u16, if (irq < 8) PIC1_DATA else PIC2_DATA);
const old = inb(port); // Retrieve the current mask. const old = x86.io.inb(port); // Retrieve the current mask.
// Mask or unmask the interrupt. // Mask or unmask the interrupt.
const shift = @truncate(u3, irq % 8); const shift = @truncate(u3, irq % 8);
// const shift = @truncate(u3, if (irq < 8) irq else irq - 8); // const shift = @truncate(u3, if (irq < 8) irq else irq - 8);
const bit = @as(u8, 1) << shift; const bit = @as(u8, 1) << shift;
if (mask) outb(port, old | bit); if (mask) x86.io.outb(port, old | bit);
if (!mask) outb(port, old & ~bit); if (!mask) x86.io.outb(port, old & ~bit);
const new = inb(port); // Retrieve the current mask. // TODO uncomment
// const new = x86.io.inb(port); // Retrieve the current mask.
} }
// configures the chan0 with a rate generator, which will trigger irq0 // configures the chan0 with a rate generator, which will trigger irq0
@ -189,10 +192,11 @@ pub const divisor = 2685;
pub const tick = 2251; // f = 1.193182 MHz, TODO: turn into a function pub const tick = 2251; // f = 1.193182 MHz, TODO: turn into a function
pub fn configPIT() void { pub fn configPIT() void {
const chanNum = 0; const chanNum = 0;
const chan = PIT_CHAN0; // const chan = PIT_CHAN0;
const LOHI = 0b11; // bit4 | bit5 const LOHI = 0b11; // bit4 | bit5
const PITMODE_RATE_GEN = 0x2; const PITMODE_RATE_GEN = 0x2;
outb(PIT_CMD, chanNum << 6 | LOHI << 4 | PITMODE_RATE_GEN << 1);
outb(PIT_CHAN0, divisor & 0xff); x86.io.outb(PIT_CMD, chanNum << 6 | LOHI << 4 | PITMODE_RATE_GEN << 1);
outb(PIT_CHAN0, divisor >> 8); x86.io.outb(PIT_CHAN0, divisor & 0xff);
x86.io.outb(PIT_CHAN0, divisor >> 8);
} }

View file

@ -1,4 +1,4 @@
usingnamespace @import("index.zig"); const idt = @import("idt.zig");
// Interrupt Service Routines defined externally in assembly. // Interrupt Service Routines defined externally in assembly.
extern fn isr0() void; extern fn isr0() void;
@ -65,9 +65,9 @@ pub const Context = packed struct {
esp: u32, esp: u32,
ss: u32, ss: u32,
pub inline fn setReturnValue(self: *volatile Context, value: var) void { // pub inline fn setReturnValue(self: *volatile Context, value: var) void {
self.registers.eax = if (@TypeOf(value) == bool) @boolToInt(value) else @intCast(u32, value); // self.registers.eax = if (@TypeOf(value) == bool) @boolToInt(value) else @intCast(u32, value);
} // }
}; };
// Structure holding general purpose registers as saved by PUSHA. // Structure holding general purpose registers as saved by PUSHA.

View file

@ -1,7 +1,7 @@
pub inline fn ltr(desc: u16) void { pub inline fn ltr(desc: u16) void {
asm volatile ("ltr %[desc]" asm volatile ("ltr %[desc]"
: :
: [desc] "r" (desc) : [desc] "r" (desc),
); );
} }
@ -30,18 +30,18 @@ pub inline fn int3() void {
pub inline fn lidt(idtr: usize) void { pub inline fn lidt(idtr: usize) void {
asm volatile ("lidt (%[idtr])" asm volatile ("lidt (%[idtr])"
: :
: [idtr] "r" (idtr) : [idtr] "r" (idtr),
); );
} }
pub fn cr2() usize { pub fn cr2() usize {
return asm volatile ("movl %%cr2, %[result]" return asm volatile ("movl %%cr2, %[result]"
: [result] "=r" (-> usize) : [result] "=r" (-> usize),
); );
} }
pub fn dr7() usize { pub fn dr7() usize {
return asm volatile ("movl %%dr7, %[result]" return asm volatile ("movl %%dr7, %[result]"
: [result] "=r" (-> usize) : [result] "=r" (-> usize),
); );
} }

View file

@ -2,32 +2,32 @@ usingnamespace @import("../index.zig");
pub inline fn inb(port: u16) u8 { pub inline fn inb(port: u16) u8 {
return asm volatile ("inb %[port], %[result]" return asm volatile ("inb %[port], %[result]"
: [result] "={al}" (-> u8) : [result] "={al}" (-> u8),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
); );
} }
pub inline fn inw(port: u16) u16 { pub inline fn inw(port: u16) u16 {
return asm volatile ("inw %[port], %[result]" return asm volatile ("inw %[port], %[result]"
: [result] "={ax}" (-> u16) : [result] "={ax}" (-> u16),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
); );
} }
pub inline fn inl(port: u16) u32 { pub inline fn inl(port: u16) u32 {
return asm volatile ("inl %[port], %[result]" return asm volatile ("inl %[port], %[result]"
: [result] "={eax}" (-> u32) : [result] "={eax}" (-> u32),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
); );
} }
pub inline fn insl(port: u16, addr: var, cnt: usize) void { pub inline fn insl(port: u16, addr: anytype, cnt: usize) void {
asm volatile ("cld; repne; insl;" asm volatile ("cld; repne; insl;"
: [addr] "={edi}" (addr), : [addr] "={edi}" (addr),
[cnt] "={ecx}" (cnt) [cnt] "={ecx}" (cnt),
: [port] "{dx}" (port), : [port] "{dx}" (port),
[addr] "0" (addr), [addr] "0" (addr),
[cnt] "1" (cnt) [cnt] "1" (cnt),
: "memory", "cc" : "memory", "cc"
); );
} }
@ -36,7 +36,7 @@ pub inline fn outb(port: u16, value: u8) void {
asm volatile ("outb %[value], %[port]" asm volatile ("outb %[value], %[port]"
: :
: [value] "{al}" (value), : [value] "{al}" (value),
[port] "N{dx}" (port) [port] "N{dx}" (port),
); );
} }
@ -44,7 +44,7 @@ pub inline fn outw(port: u16, value: u16) void {
asm volatile ("outw %[value], %[port]" asm volatile ("outw %[value], %[port]"
: :
: [value] "{ax}" (value), : [value] "{ax}" (value),
[port] "N{dx}" (port) [port] "N{dx}" (port),
); );
} }
@ -52,6 +52,6 @@ pub inline fn outl(port: u16, value: u32) void {
asm volatile ("outl %[value], %[port]" asm volatile ("outl %[value], %[port]"
: :
: [value] "{eax}" (value), : [value] "{eax}" (value),
[port] "N{dx}" (port) [port] "N{dx}" (port),
); );
} }

View file

@ -1,10 +1,12 @@
usingnamespace @import("index.zig"); const std = @import("std");
const kernel = @import("kernel");
const x86 = @import("x86");
/// x86 specific intialization /// x86 specific intialization
pub fn x86_main(info: *const kernel.multiboot.MultibootInfo) void { pub fn x86_main(info: *const kernel.multiboot.MultibootInfo) void {
gdt.initialize(); x86.gdt.initialize();
idt.initialize(); x86.idt.initialize();
pmem.initialize(info); x86.pmem.initialize(info);
paging.initialize(); x86.paging.initialize();
sti(); x86.instr.sti();
} }

View file

@ -1,4 +1,6 @@
usingnamespace @import("index.zig"); const std = @import("std");
const kernel = @import("kernel");
const x86 = @import("x86");
extern fn setupPaging(phys_pd: usize) void; extern fn setupPaging(phys_pd: usize) void;
@ -17,7 +19,7 @@ pub var pageDirectory: [1024]PageEntry align(4096) linksection(".bss") = [_]Page
// TODO: inline these // TODO: inline these
fn pageBase(virt: usize) usize { fn pageBase(virt: usize) usize {
return virt & (~PAGE_SIZE +% 1); return virt & (~x86.PAGE_SIZE +% 1);
} }
pub fn pde(virt: usize) *PageEntry { pub fn pde(virt: usize) *PageEntry {
return &PD[virt >> 22]; //relies on recursive mapping return &PD[virt >> 22]; //relies on recursive mapping
@ -34,18 +36,18 @@ pub fn translate(virt: usize) ?usize {
pub fn unmap(virt: usize) void { pub fn unmap(virt: usize) void {
if (translate(virt)) |phys| { if (translate(virt)) |phys| {
pmem.free(phys); x86.pmem.free(phys);
} else { } else {
kernel.println("can't unmap 0x{x} because it is not mapped.", .{virt}); kernel.vga.println("can't unmap 0x{x} because it is not mapped.", .{virt});
} }
} }
pub fn mmap(virt: usize, phys: ?usize) !void { pub fn mmap(virt: usize, phys: ?usize) !void {
//TODO: support hugepages //TODO: support hugepages
// allocate a page directory if there is none // allocate a page directory if there is none
if (pde(virt).* == 0) pde(virt).* = (try pmem.allocate()) | WRITE | PRESENT; if (pde(virt).* == 0) pde(virt).* = (try x86.pmem.allocate()) | WRITE | PRESENT;
// allocate a frame if phys isn't specified // allocate a frame if phys isn't specified
pte(virt).* = (if (phys) |p| p else try pmem.allocate()) | PRESENT; pte(virt).* = (if (phys) |p| p else try x86.pmem.allocate()) | PRESENT;
} }
pub fn initialize() void { pub fn initialize() void {
@ -57,7 +59,7 @@ pub fn initialize() void {
p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE; p2[1023] = @ptrToInt(&p2[0]) | PRESENT | WRITE;
// TODO: verify is this a hack? // TODO: verify is this a hack?
assert(pmem.stack_end < kernel.layout.IDENTITY); std.debug.assert(x86.pmem.stack_end < kernel.layout.IDENTITY);
setupPaging(@ptrToInt(&pageDirectory[0])); //asm routine setupPaging(@ptrToInt(&pageDirectory[0])); //asm routine
} }
@ -67,12 +69,12 @@ pub fn format() void {
i = 0; i = 0;
while (i < 1024) : (i += 1) { while (i < 1024) : (i += 1) {
if (PD[i] == 0) continue; if (PD[i] == 0) continue;
kernel.println("p2[{}] -> 0x{x}", .{ i, PD[i] }); kernel.vga.println("p2[{}] -> 0x{x}", .{ i, PD[i] });
if (PD[i] & HUGE != 0) continue; if (PD[i] & HUGE != 0) 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) kernel.println("p2[{}]p1[{}] -> 0x{x}", .{ i, j, entry }); if (entry != 0) kernel.vga.println("p2[{}]p1[{}] -> 0x{x}", .{ i, j, entry });
} }
} }
} }

View file

@ -1,4 +1,6 @@
usingnamespace @import("index.zig"); const std = @import("std");
const kernel = @import("kernel");
const x86 = @import("x86");
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.
@ -11,13 +13,13 @@ pub inline fn pageAlign(address: u32) u32 {
// 4095 -> 4096 // 4095 -> 4096
// 4096 -> 4096 // 4096 -> 4096
// 4097 -> 8192 // 4097 -> 8192
return (address + PAGE_SIZE - 1) & (~PAGE_SIZE +% 1); return (address + x86.PAGE_SIZE - 1) & (~x86.PAGE_SIZE +% 1);
} }
// Return the amount of variable elements (in bytes). // Return the amount of variable elements (in bytes).
// //
pub fn available() usize { pub fn available() usize {
return stack_index * PAGE_SIZE; return stack_index * x86.PAGE_SIZE;
} }
pub inline fn available_MiB() usize { pub inline fn available_MiB() usize {
@ -52,8 +54,8 @@ pub fn free(address: usize) void {
// //
pub fn initialize(info: *const kernel.multiboot.MultibootInfo) void { pub fn initialize(info: *const kernel.multiboot.MultibootInfo) void {
// Ensure the bootloader has given us the memory map. // Ensure the bootloader has given us the memory map.
assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEMORY) != 0); std.debug.assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEMORY) != 0);
assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEM_MAP) != 0); std.debug.assert((info.flags & kernel.multiboot.MULTIBOOT_INFO_MEM_MAP) != 0);
// TODO: WHAT WHY WHAAAAT, must check back here later // TODO: WHAT WHY WHAAAAT, must check back here later
// Place stack at 0x200000 so that in the future I trigger a // Place stack at 0x200000 so that in the future I trigger a
@ -64,7 +66,7 @@ pub fn initialize(info: *const kernel.multiboot.MultibootInfo) void {
// stack = @intToPtr([*]usize, pageAlign(info.mods_addr)); // stack = @intToPtr([*]usize, pageAlign(info.mods_addr));
// Calculate the approximate size of the stack based on the amount of total upper memory. // Calculate the approximate size of the stack based on the amount of total upper memory.
stack_size = ((info.mem_upper * 1024) / PAGE_SIZE) * @sizeOf(usize); stack_size = ((info.mem_upper * 1024) / x86.PAGE_SIZE) * @sizeOf(usize);
stack_end = pageAlign(@ptrToInt(stack) + stack_size); stack_end = pageAlign(@ptrToInt(stack) + stack_size);
var map: usize = info.mmap_addr; var map: usize = info.mmap_addr;
@ -78,17 +80,16 @@ pub fn initialize(info: *const kernel.multiboot.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 == kernel.multiboot.MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += PAGE_SIZE) if (entry.type == kernel.multiboot.MULTIBOOT_MEMORY_AVAILABLE) while (start < end) : (start += x86.PAGE_SIZE)
free(start); free(start);
// Go to the next entry in the memory map. // Go to the next entry in the memory map.
map += entry.size + @sizeOf(@TypeOf(entry.size)); map += entry.size + @sizeOf(@TypeOf(entry.size));
} }
const a = available(); kernel.vga.println("available memory: {d} MiB ", .{available() / 1024 / 1024});
kernel.println("available memory: {d} MiB ", .{available() / 1024 / 1024});
} }
pub fn format() void { pub fn format() void {
kernel.println("physframes left: {d} ({d} MiB)", .{ stack_index, available_MiB() }); kernel.vga.println("physframes left: {d} ({d} MiB)", .{ stack_index, available_MiB() });
} }

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator;
/// DeltaQueue is a singly-linked list where each /// DeltaQueue is a singly-linked list where each
/// node has a counter. Each counter is relative /// node has a counter. Each counter is relative

View file

@ -1,24 +1,25 @@
pub usingnamespace @import("common.zig"); // pub usingnamespace @import("common.zig");
pub usingnamespace @import("delta_queue.zig"); // pub usingnamespace @import("delta_queue.zig");
pub usingnamespace @import("ring_buffer.zig"); // pub usingnamespace @import("ring_buffer.zig");
pub usingnamespace @import("vga.zig");
///drivers pub const vga = @import("vga.zig");
pub const driver = @import("driver/index.zig");
///arch //drivers
// pub const driver = @import("driver/index.zig");
//arch
pub const x86 = @import("arch/x86/index.zig"); pub const x86 = @import("arch/x86/index.zig");
///core //core
pub const constants = @import("constants.zig"); pub const constants = @import("constants.zig");
pub const layout = @import("layout.zig"); pub const layout = @import("layout.zig");
pub const multiboot = @import("multiboot.zig"); pub const multiboot = @import("multiboot.zig");
pub const vmem = @import("vmem.zig"); pub const vmem = @import("vmem.zig");
pub const task = @import("task.zig"); // pub const task = @import("task.zig");
pub const time = @import("time.zig"); pub const time = @import("time.zig");
///extra //extra
pub const console = @import("console.zig"); // pub const console = @import("console.zig");
pub const bio = @import("bio.zig"); // pub const bio = @import("bio.zig");
pub const pci = @import("pci/pci.zig"); // pub const pci = @import("pci/pci.zig");
pub const ps2 = @import("ps2.zig"); // pub const ps2 = @import("ps2.zig");

View file

@ -1,14 +1,16 @@
usingnamespace @import("kernel"); const std = @import("std");
const builtin = std.builtin;
const kernel = @import("index.zig");
// Place the header at the very beginning of the binary. // Place the header at the very beginning of the binary.
export const multiboot_header align(4) linksection(".multiboot") = multiboot: { export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
const MAGIC = @as(u32, 0x1BADB002); // multiboot magic const MAGIC = @as(u32, 0x1BADB002); // multiboot magic
const ALIGN = @as(u32, 1 << 0); // Align loaded modules at 4k const ALIGN = @as(u32, 1 << 0); // Align loaded modules at 4k
const MEMINFO = @as(u32, 1 << 1); // Receive a memory map from the bootloader. const MEMINFO = @as(u32, 1 << 1); // Receive a memory map from the bootloader.
const ADDR = @as(u32, 1 << 16); // Load specific addr // const ADDR = @as(u32, 1 << 16); // Load specific addr
const FLAGS = ALIGN | MEMINFO; // Combine the flags. const FLAGS = ALIGN | MEMINFO; // Combine the flags.
break :multiboot multiboot.MultibootHeader{ break :multiboot kernel.multiboot.MultibootHeader{
.magic = MAGIC, .magic = MAGIC,
.flags = FLAGS, .flags = FLAGS,
.checksum = ~(MAGIC +% FLAGS) +% 1, .checksum = ~(MAGIC +% FLAGS) +% 1,
@ -16,32 +18,32 @@ export const multiboot_header align(4) linksection(".multiboot") = multiboot: {
}; };
// arch independant initialization // arch independant initialization
export fn kmain(magic: u32, info: *const multiboot.MultibootInfo) noreturn { export fn kmain(magic: u32, info: *const kernel.multiboot.MultibootInfo) noreturn {
assert(magic == multiboot.MULTIBOOT_BOOTLOADER_MAGIC); std.debug.assert(magic == kernel.multiboot.MULTIBOOT_BOOTLOADER_MAGIC);
clear(); kernel.vga.clear();
println("--- x86 initialization ---", .{}); kernel.vga.println("--- x86 initialization ---", .{});
x86.x86_main(info); kernel.x86.x86_main(info);
println("--- core initialization ---", .{}); kernel.vga.println("--- core initialization ---", .{});
vmem.init(); kernel.vmem.init();
pci.scan(); kernel.pci.scan();
println("--- finished booting --- ", .{}); kernel.vga.println("--- finished booting --- ", .{});
task.cleaner_task = task.new(@ptrToInt(task.cleaner_loop)) catch unreachable; // kernel.task.cleaner_task = kernel.task.new(@ptrToInt(kernel.task.cleaner_loop)) catch unreachable;
_ = task.new(@ptrToInt(topbar)) catch unreachable; // _ = kernel.task.new(@ptrToInt(kernel.vga.topbar)) catch unreachable;
_ = task.new(@ptrToInt(console.loop)) catch unreachable; // _ = kernel.task.new(@ptrToInt(kernel.console.loop)) catch unreachable;
var buf = vmem.allocator.create([512]u8) catch unreachable; // var buf = kernel.vmem.allocator.create([512]u8) catch unreachable;
println("buf at 0x{x}", .{@ptrToInt(buf)}); // kernel.vga.println("buf at 0x{x}", .{@ptrToInt(buf)});
driver.ide.first_ide_drive.read(2, buf); // kernel.driver.ide.first_ide_drive.read(2, buf);
const sig = buf[56..58]; // const sig = buf[56..58];
println("sig: {x}", .{sig}); // kernel.vga.println("sig: {x}", .{sig});
task.terminate(); // kernel.task.terminate();
} }
pub fn panic(a: []const u8, b: ?*builtin.StackTrace) noreturn { // pub fn panic(a: []const u8, b: ?*builtin.StackTrace) noreturn {
println("{}", .{a}); // kernel.vga.println("{}", .{a});
println("{}", .{b}); // kernel.vga.println("{}", .{b});
while (true) asm volatile ("hlt"); // while (true) asm volatile ("hlt");
} // }

View file

@ -29,16 +29,16 @@ pub const MultibootInfo = packed struct {
mods_count: u32, mods_count: u32,
mods_addr: u32, mods_addr: u32,
syms: extern union { syms: packed union {
// present if flags[4] // present if flags[4]
nlist: extern struct { nlist: packed struct {
tabsize: u32, tabsize: u32,
strsize: u32, strsize: u32,
addr: u32, addr: u32,
_reserved: u32, _reserved: u32,
}, },
// present if flags[5] // present if flags[5]
shdr: extern struct { shdr: packed struct {
num: u32, num: u32,
size: u32, size: u32,
addr: u32, addr: u32,
@ -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.
pub const MultibootHeader = packed struct { pub const MultibootHeader = extern 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.

View file

@ -1,4 +1,5 @@
usingnamespace @import("index.zig"); const kernel = @import("index.zig");
const x86 = @import("x86");
pub var offset_us: u64 = 0; pub var offset_us: u64 = 0;
pub var task_slice_remaining: u64 = 0; pub var task_slice_remaining: u64 = 0;
@ -8,14 +9,14 @@ pub fn increment() void {
offset_us += tick; //global time counter offset_us += tick; //global time counter
var should_preempt = task.wakeup_tick(tick); var should_preempt = kernel.task.wakeup_tick(tick);
if (task_slice_remaining != 0) { if (task_slice_remaining != 0) {
// There is a time slice length // There is a time slice length
if (task_slice_remaining <= tick) should_preempt = true; if (task_slice_remaining <= tick) should_preempt = true;
if (task_slice_remaining > tick) task_slice_remaining -= tick; if (task_slice_remaining > tick) task_slice_remaining -= tick;
} }
if (should_preempt) task.preempt(); if (should_preempt) kernel.task.preempt();
} }
pub fn uptime() void { pub fn uptime() void {
@ -23,9 +24,9 @@ pub fn uptime() void {
const offset_s: u64 = offset_ms / 1000; const offset_s: u64 = offset_ms / 1000;
offset_ms = @mod(offset_ms / 100, 10); offset_ms = @mod(offset_ms / 100, 10);
print("{}.{:.3}", .{ offset_s, offset_ms }); kernel.vga.print("{}.{:.3}", .{ offset_s, offset_ms });
} }
pub fn utilisation() void { pub fn utilisation() void {
print("{}%", .{100 * (offset_us - task.CPU_idle_time) / offset_us}); kernel.vga.print("{}%", .{100 * (offset_us - kernel.task.CPU_idle_time) / offset_us});
} }

View file

@ -1,7 +1,6 @@
usingnamespace @import("index.zig"); const std = @import("std");
// const time = @import("time.zig"); const kernel = @import("index.zig");
// const x86 = @import("arch/x86/index.zig");
// const std = @import("std");
// Screen size. // Screen size.
pub const VGA_WIDTH = 80; pub const VGA_WIDTH = 80;
pub const VGA_HEIGHT = 25; pub const VGA_HEIGHT = 25;
@ -42,23 +41,26 @@ pub const VGAEntry = packed struct {
// Enable hardware cursor. // Enable hardware cursor.
pub fn enableCursor() void { pub fn enableCursor() void {
outb(0x3D4, 0x0A); kernel.x86.io.outb(0x3D4, 0x0A);
outb(0x3D5, 0x00); kernel.x86.io.outb(0x3D5, 0x00);
} }
// Disable hardware cursor. // Disable hardware cursor.
pub fn disableCursor() void { pub fn disableCursor() void {
outb(0x3D4, 0x0A); kernel.x86.io.outb(0x3D4, 0x0A);
outb(0x3D5, 1 << 5); kernel.x86.io.outb(0x3D5, 1 << 5);
} }
const Errors = error{}; const Errors = error{};
pub fn print(comptime format: []const u8, args: var) void { pub fn print(comptime format: []const u8, args: anytype) void {
var a = std.fmt.format({}, Errors, printCallback, format, args); try std.fmt.format(.{ .writeAll = printCallback }, format, args);
} }
pub fn println(comptime format: []const u8, args: var) void {
var a = print(format ++ "\n", args); pub fn println(comptime format: []const u8, args: anytype) void {
print(format ++ "\n", args);
} }
// const time = @import("time.zig");
pub fn clear() void { pub fn clear() void {
vga.clear(); vga.clear();
} }
@ -73,11 +75,11 @@ pub fn topbar() void {
vga.cursor = 0; vga.cursor = 0;
vga.cursor_enabled = false; vga.cursor_enabled = false;
time.uptime(); kernel.time.uptime();
print(" | ", .{}); print(" | ", .{});
time.utilisation(); kernel.time.utilisation();
print(" | ", .{}); print(" | ", .{});
task.format_short(); kernel.task.format_short();
println("", .{}); println("", .{});
vga.cursor_enabled = true; vga.cursor_enabled = true;
@ -85,11 +87,11 @@ pub fn topbar() void {
vga.background = bg; vga.background = bg;
vga.foreground = fg; vga.foreground = fg;
task.usleep(50 * 1000) catch unreachable; // 60ms kernel.task.usleep(50 * 1000) catch unreachable; // 60ms
} }
} }
fn printCallback(context: void, string: []const u8) Errors!void { fn printCallback(string: []const u8) Errors!void {
vga.writeString(string); vga.writeString(string);
} }
@ -182,10 +184,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 {
x86.outb(0x3D4, 0x0F); kernel.x86.io.outb(0x3D4, 0x0F);
x86.outb(0x3D5, @truncate(u8, self.cursor)); kernel.x86.io.outb(0x3D5, @truncate(u8, self.cursor));
x86.outb(0x3D4, 0x0E); kernel.x86.io.outb(0x3D4, 0x0E);
x86.outb(0x3D5, @truncate(u8, self.cursor >> 8)); kernel.x86.io.outb(0x3D5, @truncate(u8, self.cursor >> 8));
} }
//// ////
@ -195,11 +197,11 @@ const VGA = struct {
pub fn fetchCursor(self: *VGA) void { pub fn fetchCursor(self: *VGA) void {
var cursor: usize = 0; var cursor: usize = 0;
x86.outb(0x3D4, 0x0E); kernel.x86.io.outb(0x3D4, 0x0E);
cursor |= usize(x86.inb(0x3D5)) << 8; cursor |= usize(kernel.x86.io.inb(0x3D5)) << 8;
x86.outb(0x3D4, 0x0F); kernel.x86.outb(0x3D4, 0x0F);
cursor |= x86.inb(0x3D5); cursor |= kernel.x86.io.inb(0x3D5);
self.cursor = cursor; self.cursor = cursor;
} }

View file

@ -1,4 +1,7 @@
pub usingnamespace @import("index.zig"); const std = @import("std");
const kernel = @import("kernel");
const x86 = @import("x86");
pub var allocator: std.mem.Allocator = undefined; pub var allocator: std.mem.Allocator = undefined;
// TODO: make a better memory allocator // TODO: make a better memory allocator
@ -7,7 +10,7 @@ pub var allocator: std.mem.Allocator = undefined;
// - no defragmentation // - no defragmentation
// - no allocation bigger than a page // - no allocation bigger than a page
const stack_size: usize = (layout.HEAP_END - layout.HEAP) / x86.PAGE_SIZE; const stack_size: usize = (kernel.layout.HEAP_END - kernel.layout.HEAP) / kernel.x86.PAGE_SIZE;
var stack_index: usize = 0; // Index into the stack. var stack_index: usize = 0; // Index into the stack.
var stack: [stack_size]usize = undefined; // Stack of free virtual addresses var stack: [stack_size]usize = undefined; // Stack of free virtual addresses
@ -32,7 +35,7 @@ fn realloc(
) ![]u8 { ) ![]u8 {
if (old_mem.len == 0) { if (old_mem.len == 0) {
// new allocation // new allocation
assert(new_byte_count < x86.PAGE_SIZE); // this allocator only support 1:1 mapping std.debug.assert(new_byte_count < x86.PAGE_SIZE); // this allocator only support 1:1 mapping
if (available() == 0) return error.OutOfMemory; if (available() == 0) return error.OutOfMemory;
stack_index -= 1; stack_index -= 1;
var vaddr: usize = stack[stack_index]; var vaddr: usize = stack[stack_index];
@ -44,7 +47,7 @@ fn realloc(
dealloc(@ptrToInt(&old_mem[0])); dealloc(@ptrToInt(&old_mem[0]));
return &[_]u8{}; return &[_]u8{};
} }
println("vmem: unsupported allocator operation", .{}); kernel.vga.println("vmem: unsupported allocator operation", .{});
x86.hang(); x86.hang();
// return undefined; // return undefined;
} }
@ -62,7 +65,7 @@ fn shrink(
return &[_]u8{}; return &[_]u8{};
} }
println("vmem doesn't support shrinking, {}, {}, {}, {}", .{ kernel.vga.println("vmem doesn't support shrinking, {}, {}, {}, {}", .{
old_mem, old_mem,
old_alignment, old_alignment,
new_byte_count, new_byte_count,
@ -77,8 +80,8 @@ pub fn init() void {
.reallocFn = realloc, .reallocFn = realloc,
.shrinkFn = shrink, .shrinkFn = shrink,
}; };
var addr: usize = layout.HEAP; var addr: usize = kernel.layout.HEAP;
while (addr < layout.HEAP_END) : (addr += x86.PAGE_SIZE) { while (addr < kernel.layout.HEAP_END) : (addr += x86.PAGE_SIZE) {
stack[stack_index] = addr; stack[stack_index] = addr;
stack_index += 1; stack_index += 1;
} }