feat: add scripts/new-adapter.sh to scaffold adapter crates with consistent structure
This commit is contained in:
346
scripts/new-adapter.sh
Executable file
346
scripts/new-adapter.sh
Executable file
@@ -0,0 +1,346 @@
|
|||||||
|
#!/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"
|
||||||
Reference in New Issue
Block a user