printing debug messages to serial only
This commit is contained in:
@@ -120,3 +120,22 @@ pub const Console = struct {
|
|||||||
while (x < self.fb.width) : (x += 1) dst[x] = src[x];
|
while (x < self.fb.width) : (x += 1) dst[x] = src[x];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const SerialConsole = struct {
|
||||||
|
/// Serial-only output: goes to the machine-readable log but *not* the framebuffer,
|
||||||
|
/// so debug and test detail stays out of the on-screen console. These are free
|
||||||
|
/// functions, not `Console` methods, because serial has no dependency on the
|
||||||
|
/// framebuffer — they work even before `con` is initialised.
|
||||||
|
pub fn debugWrite(bytes: []const u8) void {
|
||||||
|
arch.serialWrite(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formatted serial-only output, e.g. `debugPrint("x={d}\n", .{x})`. Truncates
|
||||||
|
/// past 256 bytes, like `Console.print`.
|
||||||
|
pub fn debugPrint(comptime fmt: []const u8, args: anytype) void {
|
||||||
|
var buf: [256]u8 = undefined;
|
||||||
|
debugWrite(std.fmt.bufPrint(&buf, fmt, args) catch return);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
+33
-26
@@ -32,6 +32,7 @@ fn kmain(boot_info: *const BootInfo) noreturn {
|
|||||||
arch.serialInit(); // machine-readable log; console mirrors to it
|
arch.serialInit(); // machine-readable log; console mirrors to it
|
||||||
|
|
||||||
const fb = boot_info.framebuffer;
|
const fb = boot_info.framebuffer;
|
||||||
|
const serial0 = console.SerialConsole;
|
||||||
con = console.Console.init(fb);
|
con = console.Console.init(fb);
|
||||||
con.clear();
|
con.clear();
|
||||||
con_ready = true;
|
con_ready = true;
|
||||||
@@ -41,13 +42,15 @@ fn kmain(boot_info: *const BootInfo) noreturn {
|
|||||||
arch.setFaultHandler(onException);
|
arch.setFaultHandler(onException);
|
||||||
arch.init();
|
arch.init();
|
||||||
|
|
||||||
con.write("danos: framebuffer console online\n");
|
con.write("danos: initalizing kernel...");
|
||||||
con.write("danos: cpu tables online (GDT, IDT, TSS)\n");
|
|
||||||
con.print(" resolution : {d}x{d}\n", .{ fb.width, fb.height });
|
serial0.debugWrite("danos: framebuffer console online\n");
|
||||||
con.print(" pitch : {d} bytes\n", .{fb.pitch});
|
serial0.debugWrite("danos: cpu tables online (GDT, IDT, TSS)\n");
|
||||||
con.print(" format : {s}\n", .{@tagName(fb.format)});
|
serial0.debugPrint(" resolution : {d}x{d}\n", .{ fb.width, fb.height });
|
||||||
con.print(" framebuffer: 0x{x:0>16}\n", .{fb.base});
|
serial0.debugPrint(" pitch : {d} bytes\n", .{fb.pitch});
|
||||||
con.print (" footprint : {d} MiB\n", .{(fb.pitch * fb.height) / (1024 * 1024)});
|
serial0.debugPrint(" format : {s}\n", .{@tagName(fb.format)});
|
||||||
|
serial0.debugPrint(" framebuffer: 0x{x:0>16}\n", .{fb.base});
|
||||||
|
serial0.debugPrint (" footdebugPrint : {d} MiB\n", .{(fb.pitch * fb.height) / (1024 * 1024)});
|
||||||
|
|
||||||
// Summarise the physical memory the loader handed us. The array is danos's
|
// Summarise the physical memory the loader handed us. The array is danos's
|
||||||
// own MemoryRegion, so this is a plain slice — no firmware layout in sight.
|
// own MemoryRegion, so this is a plain slice — no firmware layout in sight.
|
||||||
@@ -65,49 +68,49 @@ fn kmain(boot_info: *const BootInfo) noreturn {
|
|||||||
const total_bytes = total_pages * danos.page_size;
|
const total_bytes = total_pages * danos.page_size;
|
||||||
const gib = 1 << 30;
|
const gib = 1 << 30;
|
||||||
|
|
||||||
con.write("\ndanos: physical memory\n");
|
serial0.debugWrite("\ndanos: physical memory\n");
|
||||||
con.print(" total RAM : {d}.{d:0>2} GiB ({d} MiB) - RAM the firmware reported\n", .{ total_bytes / gib, (total_bytes % gib) * 100 / gib, mib(total_pages) });
|
serial0.debugPrint(" total RAM : {d}.{d:0>2} GiB ({d} MiB) - RAM the firmware reported\n", .{ total_bytes / gib, (total_bytes % gib) * 100 / gib, mib(total_pages) });
|
||||||
con.print(" usable : {d} MiB - free RAM (incl. reclaimed boot-services memory)\n", .{mib(usable_pages)});
|
serial0.debugPrint(" usable : {d} MiB - free RAM (incl. reclaimed boot-services memory)\n", .{mib(usable_pages)});
|
||||||
con.print(" reserved : {d} MiB - kernel image, boot stack, ACPI, runtime services\n", .{mib(reserved_pages)});
|
serial0.debugPrint(" reserved : {d} MiB - kernel image, boot stack, ACPI, runtime services\n", .{mib(reserved_pages)});
|
||||||
con.print(" regions : {d} - entries in the firmware memory map\n", .{regions.len});
|
serial0.debugPrint(" regions : {d} - entries in the firmware memory map\n", .{regions.len});
|
||||||
|
|
||||||
// Bring up the physical frame allocator over that map, and prove it works:
|
// Bring up the physical frame allocator over that map, and prove it works:
|
||||||
// allocate three frames, then hand them back.
|
// allocate three frames, then hand them back.
|
||||||
pmm.init(boot_info.memory_map);
|
pmm.init(boot_info.memory_map);
|
||||||
const s1 = pmm.stats();
|
const s1 = pmm.stats();
|
||||||
con.print("\ndanos: frame allocator online\n", .{});
|
serial0.debugPrint("\ndanos: frame allocator online\n", .{});
|
||||||
con.print(" free frames: {d} ({d} MiB)\n", .{ s1.free_frames, mib(s1.free_frames) });
|
serial0.debugPrint(" free frames: {d} ({d} MiB)\n", .{ s1.free_frames, mib(s1.free_frames) });
|
||||||
const f0 = pmm.alloc();
|
const f0 = pmm.alloc();
|
||||||
const f1 = pmm.alloc();
|
const f1 = pmm.alloc();
|
||||||
const f2 = pmm.alloc();
|
const f2 = pmm.alloc();
|
||||||
con.print(" alloc x3 : 0x{x} 0x{x} 0x{x}\n", .{ f0 orelse 0, f1 orelse 0, f2 orelse 0 });
|
serial0.debugPrint(" alloc x3 : 0x{x} 0x{x} 0x{x}\n", .{ f0 orelse 0, f1 orelse 0, f2 orelse 0 });
|
||||||
if (f0) |p| pmm.free(p);
|
if (f0) |p| pmm.free(p);
|
||||||
if (f1) |p| pmm.free(p);
|
if (f1) |p| pmm.free(p);
|
||||||
if (f2) |p| pmm.free(p);
|
if (f2) |p| pmm.free(p);
|
||||||
con.print(" after free : {d} frames free\n", .{pmm.stats().free_frames});
|
serial0.debugPrint(" after free : {d} frames free\n", .{pmm.stats().free_frames});
|
||||||
|
|
||||||
// Switch off the firmware's page tables onto our own (with real permissions).
|
// Switch off the firmware's page tables onto our own (with real permissions).
|
||||||
arch.enablePaging(pmm.alloc, boot_info);
|
arch.enablePaging(pmm.alloc, boot_info);
|
||||||
con.print("\ndanos: paging enabled\n", .{});
|
serial0.debugPrint("\ndanos: paging enabled\n", .{});
|
||||||
con.print(" page tables: CR3 = 0x{x:0>16}\n", .{arch.readCr3()});
|
serial0.debugPrint(" page tables: CR3 = 0x{x:0>16}\n", .{arch.readCr3()});
|
||||||
con.print(" kernel segs: {d} (mapped with W^X permissions)\n", .{boot_info.kernel_segment_count});
|
serial0.debugPrint(" kernel segs: {d} (mapped with W^X permissions)\n", .{boot_info.kernel_segment_count});
|
||||||
|
|
||||||
// Bring up the kernel heap (dynamic allocation), built on the VMM.
|
// Bring up the kernel heap (dynamic allocation), built on the VMM.
|
||||||
heap.init();
|
heap.init();
|
||||||
con.write("\ndanos: kernel heap online\n");
|
serial0.debugWrite("\ndanos: kernel heap online\n");
|
||||||
// Measure the amount of resources the kernel is actually using
|
// Measure the amount of resources the kernel is actually using
|
||||||
const s2 = pmm.stats();
|
const s2 = pmm.stats();
|
||||||
con.print(" Kernel Footprint: {d} KiB\n", .{kib(s1.free_frames - s2.free_frames)});
|
serial0.debugPrint(" Kernel FootdebugPrint: {d} KiB\n", .{kib(s1.free_frames - s2.free_frames)});
|
||||||
|
|
||||||
// Register the current context as the first task before enabling preemption.
|
// Register the current context as the first task before enabling preemption.
|
||||||
sched.init(4);
|
sched.init(4);
|
||||||
con.write("\ndanos: scheduler online\n");
|
serial0.debugWrite("\ndanos: scheduler online\n");
|
||||||
|
|
||||||
// Start the timer and unmask interrupts — the kernel now has a heartbeat, and
|
// Start the timer and unmask interrupts — the kernel now has a heartbeat, and
|
||||||
// the timer preempts among tasks.
|
// the timer preempts among tasks.
|
||||||
arch.startTimer();
|
arch.startTimer();
|
||||||
arch.enableInterrupts();
|
arch.enableInterrupts();
|
||||||
con.print("danos: timer online ({d} Hz tick; LAPIC {d} MHz, TSC {d} MHz measured)\n", .{ arch.timer_hz, arch.lapicHz() / 1_000_000, arch.tscHz() / 1_000_000 });
|
serial0.debugPrint("danos: timer online ({d} Hz tick; LAPIC {d} MHz, TSC {d} MHz measured)\n", .{ arch.timer_hz, arch.lapicHz() / 1_000_000, arch.tscHz() / 1_000_000 });
|
||||||
|
|
||||||
// In a test build (`zig build -Dtest-case=<name>`), run that case and stop.
|
// In a test build (`zig build -Dtest-case=<name>`), run that case and stop.
|
||||||
// Normal builds fall through to the idle halt.
|
// Normal builds fall through to the idle halt.
|
||||||
@@ -116,7 +119,11 @@ fn kmain(boot_info: *const BootInfo) noreturn {
|
|||||||
arch.halt();
|
arch.halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
con.write("\nkernel initialised; nothing left to do, halting.\n");
|
con.write("kernel initialised.\n");
|
||||||
|
|
||||||
|
// TODO: init process
|
||||||
|
|
||||||
|
con.write("\nnothing left to do; halting CPU.\n");
|
||||||
|
|
||||||
arch.halt();
|
arch.halt();
|
||||||
}
|
}
|
||||||
@@ -131,7 +138,7 @@ fn kib(frames: u64) u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Report a CPU exception in red and halt. There's no fault recovery yet, so any
|
/// Report a CPU exception in red and halt. There's no fault recovery yet, so any
|
||||||
/// exception is terminal — but now it prints what and where instead of silently
|
/// exception is terminal — but now it debugPrints what and where instead of silently
|
||||||
/// resetting the machine.
|
/// resetting the machine.
|
||||||
fn onException(state: *const arch.CpuState) noreturn {
|
fn onException(state: *const arch.CpuState) noreturn {
|
||||||
if (con_ready) {
|
if (con_ready) {
|
||||||
@@ -145,7 +152,7 @@ fn onException(state: *const arch.CpuState) noreturn {
|
|||||||
arch.halt();
|
arch.halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Freestanding has no OS to receive a panic. Print it to the console (if it is
|
/// Freestanding has no OS to receive a panic. debugPrint it to the console (if it is
|
||||||
/// up yet) in red, then halt.
|
/// up yet) in red, then halt.
|
||||||
pub const panic = std.debug.FullPanic(struct {
|
pub const panic = std.debug.FullPanic(struct {
|
||||||
fn panic(msg: []const u8, first_trace_addr: ?usize) noreturn {
|
fn panic(msg: []const u8, first_trace_addr: ?usize) noreturn {
|
||||||
|
|||||||
Reference in New Issue
Block a user