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.


/*
 * OS-related addresses when the OS image file is loaded
 */

pub const OS_LOAD_ADDRESS: u64 = 0x80000;	// See Memory Mapping of BCM2837 ini armv8_mmu.md

pub const KERNEL_STACK_SIZE: usize = 0x100000;
pub const KERNEL_STACK_GUARD_SIZE: usize = 0x1000; // 1KB
pub const SYSTEM_MANAGER_STACK_SIZE: usize = 0x100000; // 1MB
pub const USER_STACK_SIZE: usize = 0x100000;
pub const TEXT_SECTION_FILE_OFFSET: u64 = 0x10000;

pub const VIRTUAL_ADDR_STARTUP_BASE: u64 = 0x0000000000000000;  // identity mapping
pub const VIRTUAL_ADDR_STARTUP_END: u64 = 0x000000003fffffff;
pub const VIRTUAL_ADDR_KERNEL_BASE: u64 = 0xffffff8000000000;   // stack size starts from 0xffffff8000100000 to 0xffffff8000000000
pub const VIRTUAL_ADDR_KERNEL_STACK_GUARD_LOW_BASE: u64 = VIRTUAL_ADDR_KERNEL_BASE;
pub const VIRTUAL_ADDR_KERNEL_STACK_BASE: u64 = VIRTUAL_ADDR_KERNEL_STACK_GUARD_LOW_BASE + KERNEL_STACK_GUARD_SIZE as u64;
pub const VIRTUAL_ADDR_KERNEL_STACK_GUARD_HIGH_BASE: u64 = VIRTUAL_ADDR_KERNEL_STACK_BASE + KERNEL_STACK_SIZE as u64; // 1MB
pub const VIRTUAL_ADDR_KERNEL_TEXT_SEGMENT_BASE: u64 = VIRTUAL_ADDR_KERNEL_STACK_GUARD_HIGH_BASE + KERNEL_STACK_GUARD_SIZE as u64;

pub const VIRTUAL_ADDR_KERNEL_END: u64 = 0xffffff8003ffffff;    // 64MB
pub const VIRTUAL_ADDR_KERNEL_PUTS_CALLOUT_ADDRESS: u64 = 0xffffff8020000000;
pub const VIRTUAL_ADDR_KERNEL_UART_BASE_ADDRESS: u64 = 0xffffff8020001000;
pub const VIRTUAL_ADDR_KERNEL_INTERRUPT_BASE_ADDRESS: u64 = 0xffffff8020004000;
pub const VIRTUAL_ADDR_SYSTEM_MANAGER_BASE: u64 = 0xffffff8002000000;
pub const VIRTUAL_ADDR_SYSTEM_MANAGER_END: u64 = 0xffffff8003ffffff; // 32MB
pub const VIRTUAL_ADDR_USER_BASE: u64 = 0x0000000080000000; // stack size starts from 0x0000000080100000 to 0x0000000080000000
pub const VIRTUAL_ADDR_USER_TEXT_SEGMENT_BASE: u64 = VIRTUAL_ADDR_USER_BASE + USER_STACK_SIZE as u64;
pub const VIRTUAL_ADDR_USER_END: u64 = 0x0000000083ffffff;  // 64MB


/*
 * Process-related common information
 */
pub const MAX_NUMBER_OF_PROCESSES: usize = 64;
pub const STARTUP_PID: u64 = 0;
pub const CORE_PID: u64 = STARTUP_PID + 1;
pub const USER_MIN_PID: u64 = CORE_PID + 1;

pub const FILE_SYSTEM_BLOCK_SIZE: usize = 512;   // bytes
pub const PARAGRAPH_SIZE: usize = 8;	// bytes
pub const PAGE_SIZE: usize = 4096;	// bytes
pub const MAX_SUPPORTED_MEMORY_IN_BYTES: usize = 1024 * 1024 * 1024; // 1GB in bytes

pub const TOPIC_NAME_MAX_LENGTH: usize = 255;    // should be consistent with kernel::ipc::topic::TOPIC_NAME_MAX_LENGTH
pub const SERVER_NAME_MAX_LENGTH: usize = 255;
pub const STD_STREAM_MAX_CHARS: usize = 255;
pub const MAX_OPEN_FILES_PER_PROCESS: usize = 64;	// 64 file descriptors
pub const FILE_NAME_MAX_LENGTH: usize = 64;	// 255 characters

/*
pub const PARAGRAPH_SIZE: usize = 8; // bytes
pub const PAGE_SIZE: usize = 4096;	// bytes. PARAGRAPH_SIZE * 512
pub const CHAPTER_SIZE: usize = 16384;	// bytes (2MB). PAGE_SIZE * 512
pub const BOOK_SIZE: usize = 65536; // bytes (1GB). CHAPTER_SIZE * 512
pub const LIBRARY_SIZE: usize = 262144; // bytes (512GB). BOOK_SIZE * 512
*/

/*
 * System limits
 */
pub const MAX_MEM_PER_PROCESS: usize = 1024 * 1024 * 64;   // 64MB

#[macro_export]
macro_rules! round_up_4k {
	($x:expr) => {{
		(($x as u64 + (4096 - 1)) & !(4096 - 1))
	}};
}

#[macro_export]
macro_rules! round_down_4k {
	($x:expr) => {{
		($x as u64 & !(4096 - 1))
	}};
}

#[macro_export]
macro_rules! round_up {
	($x:expr, $align:expr) => {{
		(($x + ($align - 1)) & !($align - 1))
	}};
}

#[macro_export]
macro_rules! round_down {
	($x:expr, $align:expr) => {{
		($x & !($align - 1))
	}};
}

#[macro_export]
/* Convert Giga bytes to Bytes */
macro_rules! gigabytes_to_bytes {
    ($gigabytes:expr) => {
        ($gigabytes as u64) * 1024 * 1024 * 1024
    };
}

#[macro_export]
/* Convert MB bytes to Bytes */
macro_rules! megabytes_to_bytes {
    ($megabytes:expr) => {
        ($megabytes as u64) * 1024 * 1024
    };
}

#[macro_export]
macro_rules! bytes_to_megabytes {
    ($megabytes:expr) => {
        ($megabytes as u64) / 1024 / 1024
    };
}

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

    #[test]
    fn test_round_up_4k() {
        assert_eq!(round_up_4k!(0), 0);
        assert_eq!(round_up_4k!(1), 4096);
        assert_eq!(round_up_4k!(4096), 4096);
        assert_eq!(round_up_4k!(4097), 8192);
        assert_eq!(round_up_4k!(8192), 8192);
        assert_eq!(round_up_4k!(8193), 12288);
    }

    #[test]
    fn test_round_down_4k() {
        assert_eq!(round_down_4k!(0), 0);
        assert_eq!(round_down_4k!(1), 0);
        assert_eq!(round_down_4k!(4096), 4096);
        assert_eq!(round_down_4k!(4097), 4096);
        assert_eq!(round_down_4k!(8192), 8192);
        assert_eq!(round_down_4k!(8193), 8192);
    }

    #[test]
    fn test_round_up() {
        assert_eq!(round_up!(0, 8), 0);
        assert_eq!(round_up!(1, 8), 8);
        assert_eq!(round_up!(8, 8), 8);
        assert_eq!(round_up!(9, 8), 16);
        assert_eq!(round_up!(16, 8), 16);
        assert_eq!(round_up!(17, 8), 24);
    }

    #[test]
    fn test_round_down() {
        assert_eq!(round_down!(0, 8), 0);
        assert_eq!(round_down!(1, 8), 0);
        assert_eq!(round_down!(8, 8), 8);
        assert_eq!(round_down!(9, 8), 8);
        assert_eq!(round_down!(16, 8), 16);
        assert_eq!(round_down!(17, 8), 16);
    }

    #[test]
    fn test_gigabytes_to_bytes() {
        assert_eq!(gigabytes_to_bytes!(0), 0);
        assert_eq!(gigabytes_to_bytes!(1), 1024 * 1024 * 1024);
        assert_eq!(gigabytes_to_bytes!(2), 2 * 1024 * 1024 * 1024);
    }
}