#!/bin/bash set -euo pipefail if [ $# -lt 1 ]; then echo "Usage: $0 " echo "Example: $0 arm" echo "Creates crates/adapter-/ with the standard adapter structure." exit 1 fi ARCH="$1" CRATE="adapter-${ARCH}" DIR="crates/${CRATE}" if [ -d "$DIR" ]; then echo "Error: ${DIR} already exists." exit 1 fi echo "Creating adapter for: ${ARCH}" mkdir -p "${DIR}/src/hw" mkdir -p "${DIR}/src/mmu" mkdir -p "${DIR}/src/trap" # Cargo.toml cat > "${DIR}/Cargo.toml" < "${DIR}/src/board.rs" <<'EOF' // TODO: fill in device addresses for this platform pub const RAM_BASE: usize = 0x0; pub const RAM_SIZE: usize = 0x0; pub const UART_BASE: usize = 0x0; pub const IRQ_CONTROLLER_BASE: usize = 0x0; pub const TIMER_BASE: usize = 0x0; pub const USER_POOL_BASE: usize = 0x0; pub const USER_POOL_PAGES: usize = 256; pub const TICK_INTERVAL: u64 = 10_000_000; EOF # hw/mod.rs cat > "${DIR}/src/hw/mod.rs" <<'EOF' pub mod uart; pub mod irq; pub mod timer; EOF # hw/uart.rs cat > "${DIR}/src/hw/uart.rs" <<'EOF' use crate::board; pub struct Uart { base: usize, } impl Uart { pub fn new() -> Self { Self { base: board::UART_BASE } } pub fn put_char(&self, byte: u8) { let ptr = self.base as *mut u8; unsafe { core::ptr::write_volatile(ptr, byte) }; } pub fn write_str(&self, s: &str) { for byte in s.bytes() { self.put_char(byte); } } pub fn write_dec(&self, mut value: usize) { if value == 0 { self.put_char(b'0'); return; } let mut buf = [0u8; 20]; let mut i = 0; while value > 0 { buf[i] = b'0' + (value % 10) as u8; value /= 10; i += 1; } while i > 0 { i -= 1; self.put_char(buf[i]); } } } EOF # hw/irq.rs cat > "${DIR}/src/hw/irq.rs" <<'EOF' // TODO: implement interrupt controller for this platform // (e.g., GIC for ARM, APIC for x86) EOF # hw/timer.rs cat > "${DIR}/src/hw/timer.rs" <<'EOF' // TODO: implement timer for this platform pub fn read_time() -> u64 { 0 } pub fn init() { // TODO: set up periodic timer } pub fn handle_interrupt() { // TODO: acknowledge and reschedule timer } EOF # mmu/mod.rs cat > "${DIR}/src/mmu/mod.rs" <<'EOF' pub mod allocator; pub mod page_table; pub use allocator::init_allocator; pub use page_table::{activate, init_kernel_page_table, PAGE_SIZE}; EOF # mmu/allocator.rs cat > "${DIR}/src/mmu/allocator.rs" <<'EOF' use super::page_table::PAGE_SIZE; static mut NEXT_FREE: usize = 0; pub fn init_allocator(start: usize) { unsafe { NEXT_FREE = start; } } pub fn alloc_zeroed_page() -> usize { unsafe { let addr = NEXT_FREE; NEXT_FREE += PAGE_SIZE; core::ptr::write_bytes(addr as *mut u8, 0, PAGE_SIZE); addr } } EOF # mmu/page_table.rs cat > "${DIR}/src/mmu/page_table.rs" <<'EOF' pub const PAGE_SIZE: usize = 4096; // TODO: implement page table format for this architecture pub fn init_kernel_page_table() { // TODO: identity-map kernel memory } pub fn activate(_root: usize) { // TODO: write page table base register } EOF # trap/mod.rs cat > "${DIR}/src/trap/mod.rs" <<'EOF' // TODO: implement trap/exception vector for this architecture pub fn init() { // TODO: set trap vector register, enable interrupts } EOF # platform.rs cat > "${DIR}/src/platform.rs" <<'EOF' use domain::memory::MemoryRegion; use domain::thread::SavedContext; use platform::Platform; use types::{ address::{EntryPoint, PhysicalAddress, StackPointer}, bounded::PageCount, id::{CoreId, IrqId, ProcessId}, permission::PermissionSet, time::{Ticks, TimerDuration}, }; pub struct AdapterPlatform { num_cores: u8, } impl AdapterPlatform { pub fn new() -> Self { Self { num_cores: 1 } } } impl Platform for AdapterPlatform { fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {} fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {} fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! { loop { unsafe { core::arch::asm!("wfi") }; } } fn set_timer(&mut self, _duration: TimerDuration) {} fn current_ticks(&self) -> Ticks { Ticks::from_raw(0) } fn mask_irq(&mut self, _irq: IrqId) {} fn unmask_irq(&mut self, _irq: IrqId) {} fn send_ipi(&mut self, _target: CoreId) {} fn core_id(&self) -> CoreId { CoreId::from_raw(0) } fn num_cores(&self) -> u8 { self.num_cores } fn map_shared( &mut self, _process: ProcessId, _base: PhysicalAddress, _size: PageCount, _permissions: PermissionSet, ) {} } EOF # main.rs cat > "${DIR}/src/main.rs" <<'EOF' #![no_std] #![no_main] mod board; mod hw; mod mmu; mod platform; mod trap; use hw::uart::Uart; // TODO: add boot assembly entry point via global_asm! or a .S file unsafe extern "C" { static _bss_start: u8; static _bss_end: u8; static _heap_start: u8; } fn zero_bss() { unsafe { let start = &_bss_start as *const u8 as *mut u8; let end = &_bss_end as *const u8 as *mut u8; let len = end as usize - start as usize; core::ptr::write_bytes(start, 0, len); } } #[unsafe(no_mangle)] extern "C" fn kmain() -> ! { zero_bss(); let uart = Uart::new(); uart.write_str("k-os: booted\n"); // TODO: init MMU, traps, timer // TODO: create Kernel, boot, run loop { unsafe { core::arch::asm!("wfi") }; } } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { let uart = Uart::new(); uart.write_str("PANIC: "); if let Some(location) = info.location() { uart.write_str(location.file()); uart.put_char(b':'); uart.write_dec(location.line() as usize); } uart.put_char(b'\n'); loop { unsafe { core::arch::asm!("wfi") }; } } EOF # linker.ld — skeleton cat > "${DIR}/linker.ld" <<'EOF' /* TODO: set ENTRY and base address for this platform */ OUTPUT_ARCH(riscv) /* TODO: change to target arch */ ENTRY(_start) SECTIONS { . = 0x80000000; /* TODO: set platform entry address */ .text : { *(.text.entry) *(.text .text.*) } . = ALIGN(4096); .rodata : { *(.rodata .rodata.*) } . = ALIGN(4096); .data : { *(.data .data.*) } . = ALIGN(4096); .bss : { _bss_start = .; *(.bss .bss.*) *(.sbss .sbss.*) _bss_end = .; } . = ALIGN(4096); _stack_bottom = .; . += 0x80000; _stack_top = .; _heap_start = .; } EOF echo "" echo "Created ${DIR}/ with structure:" find "${DIR}" -type f | sort | sed "s|${DIR}/||" echo "" echo "Next steps:" echo " 1. Add \"${DIR}\" to workspace members in Cargo.toml" echo " 2. Fill in board.rs with device addresses" echo " 3. Add boot assembly (global_asm! in main.rs or .S file)" echo " 4. Update linker.ld for target architecture" echo " 5. Implement TODOs in hw/, mmu/, trap/, platform.rs"