// 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; }