feat(loader, kernel): impl part of loader and initialize kernel structure
This commit is contained in:
118
arch/x86_64/boot/early_serial_console.zig
Normal file
118
arch/x86_64/boot/early_serial_console.zig
Normal file
@@ -0,0 +1,118 @@
|
||||
const std = @import("std");
|
||||
const Cmdline = @import("cmdline.zig").Cmdline;
|
||||
const io = @import("arch").io;
|
||||
|
||||
const PREDEFINED_PORTS: [2]u16 = .{
|
||||
0x3F8, // ttyS0
|
||||
0x2F8, // ttyS1
|
||||
};
|
||||
var serial_writer: ?SerialWriter = null;
|
||||
// Parse earlyprintk argument from cmdline
|
||||
// Format: earlyprintk=serial,port,baudrate, port can either be ioport address (e.g., 0x3F8) or
|
||||
// a predefined name (e.g., ttyS0/ttyS1).
|
||||
fn parseEarlyprintk(cmdline: *const Cmdline) ?struct { port: u16, baudrate: u32 } {
|
||||
var buf = [_]u8{0} ** 32;
|
||||
const len = cmdline.parseArg("earlyprintk", &buf) orelse 0;
|
||||
if (len == 0) return null;
|
||||
const arg = buf[0..len];
|
||||
var it = std.mem.splitAny(u8, arg, ",");
|
||||
if(std.mem.eql(u8, it.next() orelse "", "serial") == false) {
|
||||
return null;
|
||||
}
|
||||
const port_str = it.next() orelse return null;
|
||||
var port: u16 = undefined;
|
||||
if (port_str.len == 5 and std.mem.startsWith(u8, port_str, "ttyS")) {
|
||||
const port_idx = std.fmt.parseInt(u8, port_str[4..5], 10) catch return null;
|
||||
if (port_idx >= PREDEFINED_PORTS.len) {
|
||||
return null;
|
||||
}
|
||||
port = PREDEFINED_PORTS[port_idx];
|
||||
} else if (std.fmt.parseInt(u16, port_str, 16) catch null) |port_val| {
|
||||
port = port_val;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
const baudrate_str = it.next() orelse return null;
|
||||
const baudrate = std.fmt.parseInt(u32, baudrate_str, 10) catch return null;
|
||||
return .{ .port = port, .baudrate = baudrate };
|
||||
}
|
||||
|
||||
fn serialInit(port: u16, baudrate: u32) void {
|
||||
const divisor: u16 = @intCast(115200 / baudrate);
|
||||
// Disable interrupts
|
||||
io.outb(port + 1, 0x00);
|
||||
// Disable FIFO
|
||||
io.outb(port + 2, 0x00);
|
||||
// Set 8 data bits, 1 stop bit, no parity
|
||||
io.outb(port + 3, 0x80);
|
||||
const c = io.inb(port + 3);
|
||||
// Enable DLAB
|
||||
io.outb(port + 3, c | 0x80);
|
||||
// Set divisor low byte
|
||||
io.outb(port + 0, @intCast(divisor & 0x00FF));
|
||||
// Set divisor high byte
|
||||
io.outb(port + 1, @intCast((divisor >> 8) & 0x00FF));
|
||||
io.outb(port + 3, c & ~@as(u8, 0x80));
|
||||
}
|
||||
|
||||
pub fn earlyConsoleInit(cmdline: *const Cmdline) void {
|
||||
const result = parseEarlyprintk(cmdline) orelse return;
|
||||
serialInit(result.port, result.baudrate);
|
||||
serial_writer = SerialWriter.init(result.port);
|
||||
}
|
||||
const SerialWriter = struct {
|
||||
port: u16,
|
||||
interface: std.Io.Writer,
|
||||
var WRITER_VTABLE: std.Io.Writer.VTable = undefined;
|
||||
pub fn init(port: u16) SerialWriter {
|
||||
WRITER_VTABLE = .{
|
||||
.drain = SerialWriter.drain,
|
||||
};
|
||||
var sw = SerialWriter{
|
||||
.port = port,
|
||||
.interface = undefined,
|
||||
};
|
||||
sw.interface = .{
|
||||
.buffer = &[0]u8{},
|
||||
.vtable = @call(.never_inline, getWriterVTable, .{}),
|
||||
};
|
||||
return sw;
|
||||
}
|
||||
pub fn writer(self: *SerialWriter) *std.Io.Writer {
|
||||
return &self.interface;
|
||||
}
|
||||
fn getWriterVTable() *const std.Io.Writer.VTable {
|
||||
return &WRITER_VTABLE;
|
||||
}
|
||||
// fn getWriterDrain() *const @TypeOf(SerialWriter.drain) {
|
||||
// return SerialWriter.drain;
|
||||
// }
|
||||
fn drain(self: *std.Io.Writer, buf: []const []const u8, splat: usize) error{}!usize {
|
||||
const sw: *SerialWriter = @fieldParentPtr("interface", self);
|
||||
var written: usize = 0;
|
||||
for (buf, 0..buf.len) |part, i| {
|
||||
const repeat = if (i == buf.len - 1) splat else 1;
|
||||
for (0..repeat) |_| {
|
||||
for (part) |c| {
|
||||
SerialWriter.putchar(sw, c);
|
||||
written += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
fn putchar(self: *const SerialWriter, c: u8) void {
|
||||
var timeout: usize = 0xffff;
|
||||
while(io.inb(self.port + 5) & 0x20 == 0 and timeout > 0) {
|
||||
timeout -= 1;
|
||||
asm volatile ("pause"
|
||||
::: .{ .memory = true }
|
||||
);
|
||||
}
|
||||
io.outb(self.port, c);
|
||||
}
|
||||
};
|
||||
pub fn dprint(comptime fmt: []const u8, args: anytype) void {
|
||||
var sw = serial_writer orelse return;
|
||||
_ = sw.writer().print(fmt, args) catch {};
|
||||
}
|
||||
Reference in New Issue
Block a user