98 lines
3.3 KiB
Zig
98 lines
3.3 KiB
Zig
// SPDX-License-Identifier: LCL-1.0
|
|
// Copyright (c) 2026 Markus Maiwald
|
|
// Stewardship: Self Sovereign Society Foundation
|
|
|
|
//! Rumpk Layer 0: UART Input Logic (Kernel Only)
|
|
//!
|
|
//! Separated from uart.zig to avoid polluting userland stubs with kernel dependencies.
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const uart = @import("uart.zig");
|
|
|
|
// Input Ring Buffer (256 bytes, power of 2 for fast masking)
|
|
const INPUT_BUFFER_SIZE = 256;
|
|
var input_buffer: [INPUT_BUFFER_SIZE]u8 = undefined;
|
|
var input_head = std.atomic.Value(u32).init(0); // Write position
|
|
var input_tail = std.atomic.Value(u32).init(0); // Read position
|
|
|
|
pub fn poll_input() void {
|
|
// Only Kernel uses this
|
|
const Kernel = struct {
|
|
extern fn ion_push_stdin(ptr: [*]const u8, len: usize) void;
|
|
extern fn kprint(s: [*]const u8) void;
|
|
};
|
|
|
|
switch (builtin.cpu.arch) {
|
|
.riscv64 => {
|
|
const thr: *volatile u8 = @ptrFromInt(uart.NS16550A_BASE + uart.NS16550A_THR);
|
|
const lsr: *volatile u8 = @ptrFromInt(uart.NS16550A_BASE + uart.NS16550A_LSR);
|
|
|
|
// Read all available bytes from UART FIFO (Limit 128 to prevent stall)
|
|
var loop_limit: usize = 0;
|
|
while ((lsr.* & 0x01) != 0 and loop_limit < 128) { // Data Ready
|
|
loop_limit += 1;
|
|
const byte = thr.*;
|
|
const byte_arr = [1]u8{byte};
|
|
|
|
// DEBUG: Trace hardware read
|
|
Kernel.kprint("[HW Read]\n");
|
|
|
|
// Forward to Kernel Input Channel
|
|
Kernel.ion_push_stdin(&byte_arr, 1);
|
|
|
|
// Add to ring buffer if not full
|
|
const head_val = input_head.load(.monotonic);
|
|
const tail_val = input_tail.load(.monotonic);
|
|
const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;
|
|
|
|
if (next_head != tail_val) {
|
|
input_buffer[head_val] = byte;
|
|
input_head.store(next_head, .monotonic);
|
|
}
|
|
}
|
|
},
|
|
.aarch64 => {
|
|
const dr: *volatile u32 = @ptrFromInt(uart.PL011_BASE + uart.PL011_DR);
|
|
const fr: *volatile u32 = @ptrFromInt(uart.PL011_BASE + uart.PL011_FR);
|
|
|
|
while ((fr.* & (1 << 4)) == 0) { // RXFE (Receive FIFO Empty) is bit 4
|
|
const byte: u8 = @truncate(dr.*);
|
|
const byte_arr = [1]u8{byte};
|
|
Kernel.ion_push_stdin(&byte_arr, 1);
|
|
|
|
const head_val = input_head.load(.monotonic);
|
|
const tail_val = input_tail.load(.monotonic);
|
|
const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;
|
|
|
|
if (next_head != tail_val) {
|
|
input_buffer[head_val] = byte;
|
|
input_head.store(next_head, .monotonic);
|
|
}
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
export fn uart_poll_input() void {
|
|
poll_input();
|
|
}
|
|
|
|
pub fn read_byte() ?u8 {
|
|
// First, poll UART to refill buffer
|
|
poll_input();
|
|
|
|
// Then read from buffer
|
|
const head_val = input_head.load(.monotonic);
|
|
const tail_val = input_tail.load(.monotonic);
|
|
|
|
if (tail_val != head_val) {
|
|
const byte = input_buffer[tail_val];
|
|
input_tail.store((tail_val + 1) % INPUT_BUFFER_SIZE, .monotonic);
|
|
return byte;
|
|
}
|
|
|
|
return null;
|
|
}
|