Files
k-os/scripts/new-adapter.sh

347 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
if [ $# -lt 1 ]; then
echo "Usage: $0 <arch>"
echo "Example: $0 arm"
echo "Creates crates/adapter-<arch>/ 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" <<EOF
[package]
name = "${CRATE}"
version = "0.1.0"
edition = "2024"
[dependencies]
types = { workspace = true }
domain = { workspace = true }
platform = { workspace = true }
kernel = { workspace = true }
[profile.release]
panic = "abort"
opt-level = "s"
[profile.dev]
panic = "abort"
EOF
# board.rs — platform-specific constants
cat > "${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<AdapterPlatform>, 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"