Merge pull request #41 from SamTebbs33/feature/serial-output
Add serial output
This commit is contained in:
commit
1b8244adfa
2 changed files with 83 additions and 0 deletions
|
@ -5,6 +5,7 @@ const arch = if (builtin.is_test) @import("../../test/kernel/arch_mock.zig") els
|
||||||
const multiboot = @import("multiboot.zig");
|
const multiboot = @import("multiboot.zig");
|
||||||
const tty = @import("tty.zig");
|
const tty = @import("tty.zig");
|
||||||
const vga = @import("vga.zig");
|
const vga = @import("vga.zig");
|
||||||
|
const serial = @import("serial.zig");
|
||||||
|
|
||||||
// Need to import this as we need the panic to be in the root source file, or zig will just use the
|
// Need to import this as we need the panic to be in the root source file, or zig will just use the
|
||||||
// builtin panic and just loop, which is what we don't want
|
// builtin panic and just loop, which is what we don't want
|
||||||
|
@ -23,6 +24,8 @@ pub export fn kmain(mb_info: *multiboot.multiboot_info_t, mb_magic: u32) void {
|
||||||
arch.init();
|
arch.init();
|
||||||
vga.init();
|
vga.init();
|
||||||
tty.init();
|
tty.init();
|
||||||
|
serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch unreachable;
|
||||||
|
|
||||||
tty.print("Hello Pluto from kernel :)\n");
|
tty.print("Hello Pluto from kernel :)\n");
|
||||||
|
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
|
|
80
src/kernel/serial.zig
Normal file
80
src/kernel/serial.zig
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
const arch = @import("arch.zig").internals;
|
||||||
|
|
||||||
|
// The LCR is the line control register
|
||||||
|
const LCR = 3;
|
||||||
|
// Maximum baudrate
|
||||||
|
const BAUD_MAX = 115200;
|
||||||
|
// 8 bits per serial character
|
||||||
|
const CHAR_LEN = 8;
|
||||||
|
// One stop bit per transmission
|
||||||
|
const SINGLE_STOP_BIT = true;
|
||||||
|
// No parity bit
|
||||||
|
const PARITY_BIT = false;
|
||||||
|
|
||||||
|
pub const DEFAULT_BAUDRATE = 38400;
|
||||||
|
|
||||||
|
const SerialError = error {
|
||||||
|
InvalidBaud
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Port = enum(u16) {
|
||||||
|
COM1 = 0x3F8,
|
||||||
|
COM2 = 0x2F8,
|
||||||
|
COM3 = 0x3E8,
|
||||||
|
COM4 = 0x2E8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compute a value that encodes the serial properties
|
||||||
|
// This is fed into the LCR (line control register)
|
||||||
|
fn lcrValue(char_len: u8, comptime stop_bit: bool, comptime parity_bit: bool, msb: u8) u8 {
|
||||||
|
var val = char_len & 0x3;
|
||||||
|
val |= (if (stop_bit) 0 else 1) << 2;
|
||||||
|
val |= (if (parity_bit) 1 else 0) << 3;
|
||||||
|
val |= (msb & 0x1) << 7;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baudDivisor(baud: u32) SerialError!u16 {
|
||||||
|
if (baud > BAUD_MAX or baud <= 0) return SerialError.InvalidBaud;
|
||||||
|
return @intCast(u16, BAUD_MAX / baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transmitIsEmpty(port: Port) bool {
|
||||||
|
return arch.inb(@enumToInt(port) + 5) & 0x20 > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Initialise a serial port to a certain baudrate
|
||||||
|
///
|
||||||
|
/// Arguments
|
||||||
|
/// IN baud: u32 - The baudrate to use. Cannot be more than MAX_BAUDRATE
|
||||||
|
/// IN port: Port - The port to initialise
|
||||||
|
///
|
||||||
|
/// Throws a SerialError if the baudrate is invalid
|
||||||
|
///
|
||||||
|
pub fn init(baud: u32, port: Port) SerialError!void {
|
||||||
|
// The baudrate is sent as a divisor of the max baud rate
|
||||||
|
const divisor: u16 = try baudDivisor(baud);
|
||||||
|
const port_int = @enumToInt(port);
|
||||||
|
// Send a byte to start setting the baudrate
|
||||||
|
arch.outb(port_int + LCR, lcrValue(0, false, false, 1));
|
||||||
|
// Send the divisor's lsb
|
||||||
|
arch.outb(port_int, @truncate(u8, divisor));
|
||||||
|
// Send the divisor's msb
|
||||||
|
arch.outb(port_int + 1, @truncate(u8, divisor >> 8));
|
||||||
|
// Send the properties to use
|
||||||
|
arch.outb(port_int + LCR, lcrValue(CHAR_LEN, SINGLE_STOP_BIT, PARITY_BIT, 0));
|
||||||
|
// Stop initialisation
|
||||||
|
arch.outb(port_int + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(char: u8, port: Port) void {
|
||||||
|
while (!transmitIsEmpty(port)) { arch.halt(); }
|
||||||
|
arch.outb(@enumToInt(port), char);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeString(str: []const u8, port: Port) void {
|
||||||
|
for (str) |char| {
|
||||||
|
write(char, port);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue