tail_core 0.1.1

Core library for the Tail operating system
Documentation
// Copyright 2025, TAIL OS. All Rights Reserved.
//
// You must obtain a written license from and pay applicable license fees to TAIL OS
// before you may reproduce, modify, or distribute this software, or any work that
// includes all or part of this software.
//
// Free development licenses are available for evaluation, research, and non-commercial
// purposes, which may include access to the source code under these terms. Redistribution
// or commercial use without a license is strictly prohibited.
//
// This file may contain contributions from others. Please review this entire file for
// other proprietary rights or license notices, as well as the TAIL OS License Guide at
// https://tail-os.com/license-guide/ for more information.
//
// For licensing inquiries, visit https://tail-os.com or email license@tail-os.com.


#[cfg(not(test))]
use core::intrinsics::volatile_load;
#[cfg(not(test))]
use core::intrinsics::volatile_store;

static mut UART_BASE_ADDRESS: u64 = 0;
static mut UART_READ_OFFSET: u64 = 0;
static mut UART_WRITE_OFFSET: u64 = 0;
static mut UART_PUT_BIT: u64 = 0;
static mut UART_GET_BIT: u64 = 0;

#[no_mangle]
pub fn set_uart(uart_base_address: u64, uart_read_offset: u64, uart_write_offset: u64, uart_put_bit: u64, uart_get_bit: u64)
{
	unsafe {
	UART_BASE_ADDRESS = uart_base_address;
	UART_READ_OFFSET = uart_read_offset;
	UART_WRITE_OFFSET = uart_write_offset;
	UART_PUT_BIT = uart_put_bit;
	UART_GET_BIT = uart_get_bit;
	}
}

#[no_mangle]
pub fn putc(c: u8)
{
	// Wait for UART to become ready to transmit
	unsafe {
	while volatile_load((UART_BASE_ADDRESS + UART_READ_OFFSET) as *mut u64) & UART_PUT_BIT !=0 {}
	volatile_store((UART_BASE_ADDRESS +  UART_WRITE_OFFSET) as *mut u64, c as u64);
	}
}

#[no_mangle]
pub fn getc() -> u8
{
	unsafe {
	while volatile_load((UART_BASE_ADDRESS + UART_READ_OFFSET) as *mut u64) & UART_GET_BIT != 0 {}
	volatile_load((UART_BASE_ADDRESS + UART_WRITE_OFFSET) as *mut u64) as u8
	}
}

#[no_mangle]
pub fn puts(msg: &str)
{
	for c in msg.chars() {
		putc(c as u8);
	}
}

// mocked function
#[cfg(test)]
pub unsafe fn volatile_load(address: *mut u64) -> u64 {
    return 'A' as u64;
}

// mocked function
#[cfg(test)]
pub unsafe fn volatile_store(address: *mut u64, value: u64)
{
    // empty
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_getc_putc() {
        let c = 'A' as u8;
        putc(c);
        assert_eq!(getc(), c);
    }

    #[test]
    fn test_puts() {
        let msg = "Hello, World!";
        puts(msg);
    }

    #[test]
    fn test_set_uart() {
        let uart_base_address = 0x3F201000;
        let uart_read_offset = 0x18;
        let uart_write_offset = 0x20;
        let uart_put_bit = 0x20;
        let uart_get_bit = 0x10;
        set_uart(uart_base_address, uart_read_offset, uart_write_offset, uart_put_bit, uart_get_bit);
    }
}