Compare commits
4 Commits
c155247f1d
...
006f9f8ac5
Author | SHA1 | Date |
---|---|---|
Drew Galbraith | 006f9f8ac5 | |
Drew Galbraith | 8206e671cd | |
Drew Galbraith | 71431189c9 | |
Drew Galbraith | f5a27156d2 |
|
@ -0,0 +1,343 @@
|
||||||
|
use crate::debug;
|
||||||
|
use crate::init;
|
||||||
|
use crate::syscall;
|
||||||
|
use crate::zion::z_cap_t;
|
||||||
|
use crate::zion::ZError;
|
||||||
|
|
||||||
|
use alloc::fmt::Debug;
|
||||||
|
|
||||||
|
const ELF_MAGIC: u32 = 0x464C457F;
|
||||||
|
|
||||||
|
const ELF_IDENT_32BIT: u8 = 0x1;
|
||||||
|
const ELF_IDENT_64BIT: u8 = 0x2;
|
||||||
|
|
||||||
|
const ELF_ENDIAN_LITTLE: u8 = 0x1;
|
||||||
|
const ELF_ENDIAN_BIG: u8 = 0x2;
|
||||||
|
|
||||||
|
const ELF_VERSION_CURRENT: u8 = 0x1;
|
||||||
|
|
||||||
|
const ELF_ABI_SYSV: u8 = 0x0;
|
||||||
|
const ELF_ABI_LINUX: u8 = 0x3;
|
||||||
|
|
||||||
|
const ELF_FILE_RELOC: u16 = 0x1;
|
||||||
|
const ELF_FILE_EXEC: u16 = 0x2;
|
||||||
|
const ELF_FILE_DYN: u16 = 0x3;
|
||||||
|
const ELF_FILE_CORE: u16 = 0x4;
|
||||||
|
|
||||||
|
const ELF_MACH_X86: u16 = 0x3;
|
||||||
|
const ELF_MACH_AMD64: u16 = 0x3e;
|
||||||
|
|
||||||
|
#[repr(C, packed(1))]
|
||||||
|
// Header spec from wikipedia: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_header
|
||||||
|
struct Elf64Header {
|
||||||
|
// 0x7F454C46 (0x7F followed by 'ELF')
|
||||||
|
magic: u32,
|
||||||
|
|
||||||
|
// 1 for 32 bit, 2 for 64 bit.
|
||||||
|
elf_class: u8,
|
||||||
|
|
||||||
|
// 1 for little, 2 for big.
|
||||||
|
endianess: u8,
|
||||||
|
|
||||||
|
// Current version is 1.
|
||||||
|
ident_version: u8,
|
||||||
|
|
||||||
|
// Target OS abi.
|
||||||
|
abi: u8,
|
||||||
|
abi_version: u8,
|
||||||
|
|
||||||
|
ident_padding: [u8; 7],
|
||||||
|
|
||||||
|
file_type: u16,
|
||||||
|
machine: u16,
|
||||||
|
version: u32,
|
||||||
|
entry: u64,
|
||||||
|
program_header_offset: u64,
|
||||||
|
section_header_offset: u64,
|
||||||
|
flags: u32,
|
||||||
|
header_size: u16,
|
||||||
|
program_header_entry_size: u16,
|
||||||
|
program_header_count: u16,
|
||||||
|
section_header_entry_size: u16,
|
||||||
|
section_header_entry_number: u16,
|
||||||
|
section_header_str_index: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Elf64Header {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let magic = self.magic;
|
||||||
|
let elf_class = match self.elf_class {
|
||||||
|
ELF_IDENT_32BIT => "32 bit",
|
||||||
|
ELF_IDENT_64BIT => "64 bit",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
let endianess = match self.endianess {
|
||||||
|
ELF_ENDIAN_LITTLE => "Little",
|
||||||
|
ELF_ENDIAN_BIG => "Big",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
let ident_version = self.ident_version;
|
||||||
|
let version = self.version;
|
||||||
|
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"ELF Header Magic: {:#x}, Class: {}, Endianess: {}, Version (ident): {}, Version: {}\n",
|
||||||
|
magic, elf_class, endianess, ident_version, version,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let abi = match self.abi {
|
||||||
|
ELF_ABI_SYSV => "SYSV",
|
||||||
|
ELF_ABI_LINUX => "Linux",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
let abi_version = self.abi_version;
|
||||||
|
|
||||||
|
f.write_fmt(format_args!("\tABI: {}, Version: {}\n", abi, abi_version))?;
|
||||||
|
|
||||||
|
let file_type = match self.file_type {
|
||||||
|
ELF_FILE_EXEC => "Executable",
|
||||||
|
ELF_FILE_RELOC => "Relocatable",
|
||||||
|
ELF_FILE_DYN => "Shared Obj",
|
||||||
|
ELF_FILE_CORE => "Core file",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
let machine = match self.machine {
|
||||||
|
ELF_MACH_X86 => "x86 (32bit)",
|
||||||
|
ELF_MACH_AMD64 => "x86-64",
|
||||||
|
_ => "Unknown",
|
||||||
|
};
|
||||||
|
|
||||||
|
let entry_point = self.entry;
|
||||||
|
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"\tFile type: {}, Machine Arch: {}, Entry point {:#x}",
|
||||||
|
file_type, machine, entry_point
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_header(elf_header: &Elf64Header) -> Result<(), ZError> {
|
||||||
|
if elf_header.magic != ELF_MAGIC {
|
||||||
|
let magic = elf_header.magic;
|
||||||
|
debug!(
|
||||||
|
"Elf header incorrect got {:#x} expected {:#x}",
|
||||||
|
magic, ELF_MAGIC
|
||||||
|
);
|
||||||
|
return Err(ZError::INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if elf_header.elf_class != ELF_IDENT_64BIT {
|
||||||
|
let class = elf_header.elf_class;
|
||||||
|
debug!(
|
||||||
|
"Elf class must be {} for 64 bit, got: {}",
|
||||||
|
ELF_IDENT_64BIT, class
|
||||||
|
);
|
||||||
|
return Err(ZError::INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if elf_header.endianess != ELF_ENDIAN_LITTLE {
|
||||||
|
let endianess = elf_header.endianess;
|
||||||
|
debug!(
|
||||||
|
"Elf endianess must be {} for little, got: {}",
|
||||||
|
ELF_ENDIAN_LITTLE, endianess
|
||||||
|
);
|
||||||
|
return Err(ZError::INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if elf_header.ident_version != ELF_VERSION_CURRENT {
|
||||||
|
let version = elf_header.ident_version;
|
||||||
|
debug!(
|
||||||
|
"Elf version (ident) must be {}, got: {}",
|
||||||
|
ELF_VERSION_CURRENT, version
|
||||||
|
);
|
||||||
|
return Err(ZError::INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if elf_header.file_type != ELF_FILE_EXEC {
|
||||||
|
let file_type = elf_header.file_type;
|
||||||
|
debug!(
|
||||||
|
"Elf file type must be {} for executable, got {:x}",
|
||||||
|
ELF_FILE_EXEC, file_type
|
||||||
|
);
|
||||||
|
return Err(ZError::INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const ELF_PROG_NULL: u32 = 0x0;
|
||||||
|
const ELF_PROG_LOAD: u32 = 0x1;
|
||||||
|
const ELF_PROG_DYNAMIC: u32 = 0x2;
|
||||||
|
const ELF_PROG_INTERP: u32 = 0x3;
|
||||||
|
const ELF_PROG_NOTE: u32 = 0x4;
|
||||||
|
const ELF_PROG_SHLIB: u32 = 0x5;
|
||||||
|
const ELF_PROG_PTHDR: u32 = 0x6;
|
||||||
|
const ELF_PROG_THREAD_LOCAL: u32 = 0x7;
|
||||||
|
|
||||||
|
// Stack unwind tables.
|
||||||
|
const ELF_PROG_GNU_EH_FRAME: u32 = 0x6474e550;
|
||||||
|
const ELF_PROG_GNU_STACK: u32 = 0x6474e551;
|
||||||
|
const ELF_PROG_GNU_RELRO: u32 = 0x6474e552;
|
||||||
|
|
||||||
|
#[repr(C, packed(1))]
|
||||||
|
struct Elf64ProgramHeader {
|
||||||
|
prog_type: u32,
|
||||||
|
flags: u32,
|
||||||
|
offset: u64,
|
||||||
|
vaddr: u64,
|
||||||
|
paddr: u64,
|
||||||
|
file_size: u64,
|
||||||
|
mem_size: u64,
|
||||||
|
align: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Elf64ProgramHeader {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
let prog_type = match self.prog_type {
|
||||||
|
ELF_PROG_NULL => "NULL",
|
||||||
|
ELF_PROG_LOAD => "LOAD",
|
||||||
|
ELF_PROG_DYNAMIC => "DYNAMIC",
|
||||||
|
ELF_PROG_INTERP => "INTERP",
|
||||||
|
ELF_PROG_NOTE => "NOTE",
|
||||||
|
ELF_PROG_SHLIB => "SHARED LIB",
|
||||||
|
ELF_PROG_PTHDR => "PROG TABLE HEADER",
|
||||||
|
ELF_PROG_THREAD_LOCAL => "THREAD LOCAL",
|
||||||
|
ELF_PROG_GNU_EH_FRAME => "GNU EH FRAME",
|
||||||
|
ELF_PROG_GNU_RELRO => "GNU RELOCATABLE",
|
||||||
|
ELF_PROG_GNU_STACK => "GNU STACK",
|
||||||
|
_ => "UNKNOWN",
|
||||||
|
};
|
||||||
|
|
||||||
|
let offset = self.offset;
|
||||||
|
let vaddr = self.vaddr;
|
||||||
|
let paddr = self.paddr;
|
||||||
|
let file_size = self.file_size;
|
||||||
|
let mem_size = self.mem_size;
|
||||||
|
let align = self.align;
|
||||||
|
f.write_fmt(format_args!(
|
||||||
|
"Type: {}, offset: {:#x}, vaddr: {:#x}, paddr: {:#x}, file_size: {:#x}, mem_size: {:#x}, align: {:#x}",
|
||||||
|
prog_type, offset, vaddr, paddr, file_size, mem_size, align
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_program_segment(
|
||||||
|
prog_header: &Elf64ProgramHeader,
|
||||||
|
file: &[u8],
|
||||||
|
vmas: z_cap_t,
|
||||||
|
) -> Result<(), ZError> {
|
||||||
|
debug!("{:?}", prog_header);
|
||||||
|
match prog_header.prog_type {
|
||||||
|
ELF_PROG_NULL
|
||||||
|
| ELF_PROG_NOTE
|
||||||
|
| ELF_PROG_PTHDR
|
||||||
|
| ELF_PROG_GNU_STACK
|
||||||
|
| ELF_PROG_GNU_RELRO
|
||||||
|
| ELF_PROG_GNU_EH_FRAME => Ok(()),
|
||||||
|
ELF_PROG_LOAD => {
|
||||||
|
let page_offset = prog_header.vaddr & 0xFFF;
|
||||||
|
let mem_size = page_offset + prog_header.mem_size;
|
||||||
|
|
||||||
|
let mem_object = crate::mem::MemoryRegion::new(mem_size)?;
|
||||||
|
|
||||||
|
for i in mem_object.mut_slice() {
|
||||||
|
*i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_start = prog_header.offset as usize;
|
||||||
|
let file_end = file_start + prog_header.file_size as usize;
|
||||||
|
let from_slice = &file[file_start..file_end];
|
||||||
|
|
||||||
|
let mem_start = page_offset as usize;
|
||||||
|
let mem_end = mem_start + (prog_header.file_size as usize);
|
||||||
|
let to_slice: &mut [u8] = &mut mem_object.mut_slice()[mem_start..mem_end];
|
||||||
|
|
||||||
|
to_slice.copy_from_slice(from_slice);
|
||||||
|
|
||||||
|
let vaddr = prog_header.vaddr - page_offset;
|
||||||
|
syscall::address_space_map_external(vmas, mem_object.cap(), vaddr)
|
||||||
|
}
|
||||||
|
ELF_PROG_DYNAMIC => {
|
||||||
|
debug!("Unimplemented dynamic elf sections.");
|
||||||
|
Err(ZError::UNIMPLEMENTED)
|
||||||
|
}
|
||||||
|
ELF_PROG_INTERP => {
|
||||||
|
debug!("Unimplemented interpreter elf sections.");
|
||||||
|
Err(ZError::UNIMPLEMENTED)
|
||||||
|
}
|
||||||
|
ELF_PROG_SHLIB => {
|
||||||
|
debug!("Unimplemented shared lib elf sections.");
|
||||||
|
Err(ZError::UNIMPLEMENTED)
|
||||||
|
}
|
||||||
|
ELF_PROG_THREAD_LOCAL => {
|
||||||
|
debug!("Unimplemented thread local elf sections.");
|
||||||
|
Err(ZError::UNIMPLEMENTED)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let prog_type = prog_header.prog_type;
|
||||||
|
debug!("Unknown elf program header type: {:#x}", prog_type);
|
||||||
|
Err(ZError::UNKNOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_elf_program(elf_file: &[u8], vmas: z_cap_t) -> Result<u64, ZError> {
|
||||||
|
assert!(elf_file.len() > size_of::<Elf64Header>());
|
||||||
|
let header: &Elf64Header = unsafe {
|
||||||
|
elf_file
|
||||||
|
.as_ptr()
|
||||||
|
.cast::<Elf64Header>()
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(ZError::NULL_PTR)?
|
||||||
|
};
|
||||||
|
debug!("{:?}", header);
|
||||||
|
validate_header(header)?;
|
||||||
|
|
||||||
|
for prog_ind in 0..header.program_header_count {
|
||||||
|
let prog_header_offset = header.program_header_offset
|
||||||
|
+ ((prog_ind as u64) * (header.program_header_entry_size as u64));
|
||||||
|
let prog_header_end = prog_header_offset + header.program_header_entry_size as u64;
|
||||||
|
let prog_header_slice = &elf_file[prog_header_offset as usize..prog_header_end as usize];
|
||||||
|
let prog_header: &Elf64ProgramHeader = unsafe {
|
||||||
|
prog_header_slice
|
||||||
|
.as_ptr()
|
||||||
|
.cast::<Elf64ProgramHeader>()
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(ZError::NULL_PTR)?
|
||||||
|
};
|
||||||
|
|
||||||
|
load_program_segment(prog_header, elf_file, vmas)?;
|
||||||
|
}
|
||||||
|
Ok(header.entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result<z_cap_t, ZError> {
|
||||||
|
let self_cap = unsafe { init::SELF_PROC_CAP };
|
||||||
|
let port_cap = syscall::port_create()?;
|
||||||
|
let port_cap_dup = syscall::cap_duplicate(port_cap, u64::MAX)?;
|
||||||
|
|
||||||
|
let (new_proc_cap, new_as_cap, foreign_port_id) =
|
||||||
|
syscall::process_spawn(self_cap, port_cap_dup)?;
|
||||||
|
|
||||||
|
let entry_point = load_elf_program(elf_file, new_as_cap)?;
|
||||||
|
|
||||||
|
let port = crate::port::PortClient::take_from(port_cap);
|
||||||
|
|
||||||
|
port.write_u64_and_cap(
|
||||||
|
crate::init::Z_INIT_SELF_PROC,
|
||||||
|
syscall::cap_duplicate(new_proc_cap, u64::MAX)?,
|
||||||
|
)?;
|
||||||
|
port.write_u64_and_cap(crate::init::Z_INIT_SELF_VMAS, new_as_cap)?;
|
||||||
|
port.write_u64_and_cap(
|
||||||
|
crate::init::Z_INIT_ENDPOINT,
|
||||||
|
syscall::cap_duplicate(unsafe { crate::init::INIT_ENDPOINT }, u64::MAX)?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let thread_cap = syscall::thread_create(new_proc_cap)?;
|
||||||
|
syscall::thread_start(thread_cap, entry_point, foreign_port_id, 0)?;
|
||||||
|
|
||||||
|
syscall::cap_release(thread_cap)?;
|
||||||
|
|
||||||
|
Ok(new_proc_cap)
|
||||||
|
}
|
|
@ -2,9 +2,9 @@ use crate::syscall;
|
||||||
use crate::zion::z_cap_t;
|
use crate::zion::z_cap_t;
|
||||||
|
|
||||||
// From /zion/include/ztypes.h
|
// From /zion/include/ztypes.h
|
||||||
const Z_INIT_SELF_PROC: u64 = 0x4000_0000;
|
pub const Z_INIT_SELF_PROC: u64 = 0x4000_0000;
|
||||||
const Z_INIT_SELF_VMAS: u64 = 0x4000_0001;
|
pub const Z_INIT_SELF_VMAS: u64 = 0x4000_0001;
|
||||||
const Z_INIT_ENDPOINT: u64 = 0x4100_0000;
|
pub const Z_INIT_ENDPOINT: u64 = 0x4100_0000;
|
||||||
|
|
||||||
pub static mut SELF_PROC_CAP: z_cap_t = 0;
|
pub static mut SELF_PROC_CAP: z_cap_t = 0;
|
||||||
pub static mut SELF_VMAS_CAP: z_cap_t = 0;
|
pub static mut SELF_VMAS_CAP: z_cap_t = 0;
|
||||||
|
|
|
@ -8,6 +8,7 @@ extern crate alloc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
|
pub mod elf;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod port;
|
pub mod port;
|
||||||
|
|
|
@ -46,6 +46,16 @@ impl MemoryRegion {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(size: u64) -> Result<Self, ZError> {
|
||||||
|
let mem_cap = syscall::memory_object_create(size)?;
|
||||||
|
let virt_addr = syscall::address_space_map(mem_cap)?;
|
||||||
|
Ok(Self {
|
||||||
|
mem_cap,
|
||||||
|
virt_addr,
|
||||||
|
size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slice<T>(&self) -> &[T] {
|
pub fn slice<T>(&self) -> &[T] {
|
||||||
unsafe {
|
unsafe {
|
||||||
slice::from_raw_parts(
|
slice::from_raw_parts(
|
||||||
|
@ -63,12 +73,20 @@ impl MemoryRegion {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cap(&self) -> z_cap_t {
|
||||||
|
self.mem_cap
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for MemoryRegion {
|
impl Drop for MemoryRegion {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
syscall::address_space_unmap(self.virt_addr, self.virt_addr + self.size)
|
// FIXME: We shouldn't have to do this manual adjustment.
|
||||||
.expect("Failed to unmap memory");
|
let mut max = self.virt_addr + self.size;
|
||||||
|
if (max & 0xFFF) != 0 {
|
||||||
|
max += 0x1000 - (max & 0xFFF);
|
||||||
|
}
|
||||||
|
syscall::address_space_unmap(self.virt_addr, max).expect("Failed to unmap memory");
|
||||||
syscall::cap_release(self.mem_cap).expect("Failed to release memory cap");
|
syscall::cap_release(self.mem_cap).expect("Failed to release memory cap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,3 +40,31 @@ impl Drop for PortServer {
|
||||||
cap_release(self.port_cap).expect("Failed to release port cap");
|
cap_release(self.port_cap).expect("Failed to release port cap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PortClient {
|
||||||
|
port_cap: z_cap_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortClient {
|
||||||
|
pub fn take_from(port_cap: z_cap_t) -> Self {
|
||||||
|
Self { port_cap }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_from(port_cap: z_cap_t) -> Result<Self, ZError> {
|
||||||
|
Ok(Self {
|
||||||
|
port_cap: cap_duplicate(port_cap, u64::MAX)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[warn(unused_results)]
|
||||||
|
pub fn write_u64_and_cap(&self, bytes: u64, cap: z_cap_t) -> Result<(), ZError> {
|
||||||
|
let mut caps: [z_cap_t; 1] = [cap];
|
||||||
|
crate::syscall::port_send(self.port_cap, &bytes.to_le_bytes(), &mut caps)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for PortClient {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
cap_release(self.port_cap).expect("Failed to release port cap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,12 +40,46 @@ pub fn debug(msg: &str) {
|
||||||
syscall(zion::kZionDebug, &req).expect("Failed to write");
|
syscall(zion::kZionDebug, &req).expect("Failed to write");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_spawn(
|
||||||
|
proc_cap: z_cap_t,
|
||||||
|
bootstrap_cap: z_cap_t,
|
||||||
|
) -> Result<(z_cap_t, z_cap_t, z_cap_t), ZError> {
|
||||||
|
let mut new_proc_cap = 0;
|
||||||
|
let mut new_as_cap = 0;
|
||||||
|
let mut new_bootstrap_cap = 0;
|
||||||
|
|
||||||
|
syscall(
|
||||||
|
zion::kZionProcessSpawn,
|
||||||
|
&zion::ZProcessSpawnReq {
|
||||||
|
proc_cap,
|
||||||
|
bootstrap_cap,
|
||||||
|
new_proc_cap: &mut new_proc_cap,
|
||||||
|
new_vmas_cap: &mut new_as_cap,
|
||||||
|
new_bootstrap_cap: &mut new_bootstrap_cap,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok((new_proc_cap, new_as_cap, new_bootstrap_cap))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_exit(code: u64) -> ! {
|
pub fn process_exit(code: u64) -> ! {
|
||||||
let _ = syscall(zion::kZionProcessExit, &zion::ZProcessExitReq { code });
|
let _ = syscall(zion::kZionProcessExit, &zion::ZProcessExitReq { code });
|
||||||
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_wait(proc_cap: z_cap_t) -> Result<u64, ZError> {
|
||||||
|
let mut err_code = 0;
|
||||||
|
syscall(
|
||||||
|
zion::kZionProcessWait,
|
||||||
|
&zion::ZProcessWaitReq {
|
||||||
|
proc_cap,
|
||||||
|
exit_code: &mut err_code,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Ok(err_code)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn thread_create(proc_cap: z_cap_t) -> Result<z_cap_t, ZError> {
|
pub fn thread_create(proc_cap: z_cap_t) -> Result<z_cap_t, ZError> {
|
||||||
let mut cap = 0;
|
let mut cap = 0;
|
||||||
syscall(
|
syscall(
|
||||||
|
@ -58,6 +92,10 @@ pub fn thread_create(proc_cap: z_cap_t) -> Result<z_cap_t, ZError> {
|
||||||
Ok(cap)
|
Ok(cap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn thread_sleep(millis: u64) -> Result<(), ZError> {
|
||||||
|
syscall(zion::kZionThreadSleep, &zion::ZThreadSleepReq { millis })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Result<(), ZError> {
|
pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Result<(), ZError> {
|
||||||
syscall(
|
syscall(
|
||||||
zion::kZionThreadStart,
|
zion::kZionThreadStart,
|
||||||
|
@ -129,6 +167,24 @@ pub fn address_space_map(vmmo_cap: z_cap_t) -> Result<u64, ZError> {
|
||||||
Ok(vaddr)
|
Ok(vaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn address_space_map_external(
|
||||||
|
vmas_cap: z_cap_t,
|
||||||
|
vmmo_cap: z_cap_t,
|
||||||
|
vaddr: u64,
|
||||||
|
) -> Result<(), ZError> {
|
||||||
|
let mut vaddr_throw: u64 = 0;
|
||||||
|
let vmas_req = zion::ZAddressSpaceMapReq {
|
||||||
|
vmmo_cap,
|
||||||
|
vmas_cap,
|
||||||
|
align: 0,
|
||||||
|
vaddr: &mut vaddr_throw as *mut u64,
|
||||||
|
vmas_offset: vaddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
syscall(zion::kZionAddressSpaceMap, &vmas_req)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZError> {
|
pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZError> {
|
||||||
syscall(
|
syscall(
|
||||||
zion::kZionAddressSpaceUnmap,
|
zion::kZionAddressSpaceUnmap,
|
||||||
|
@ -151,6 +207,20 @@ pub fn port_create() -> Result<z_cap_t, ZError> {
|
||||||
Ok(port_cap)
|
Ok(port_cap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn port_send(port_cap: z_cap_t, bytes: &[u8], caps: &mut [z_cap_t]) -> Result<(), ZError> {
|
||||||
|
syscall(
|
||||||
|
zion::kZionPortSend,
|
||||||
|
&zion::ZPortSendReq {
|
||||||
|
port_cap,
|
||||||
|
num_bytes: bytes.len() as u64,
|
||||||
|
data: bytes.as_ptr() as *const c_void,
|
||||||
|
num_caps: caps.len() as u64,
|
||||||
|
// FIXME: This shouldn't need to be mutable.
|
||||||
|
caps: caps.as_mut_ptr(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn port_recv(
|
pub fn port_recv(
|
||||||
port_cap: z_cap_t,
|
port_cap: z_cap_t,
|
||||||
bytes: &mut [u8],
|
bytes: &mut [u8],
|
||||||
|
|
|
@ -55,7 +55,13 @@ impl fmt::Debug for ZError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let str = match self {
|
let str = match self {
|
||||||
ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT",
|
ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT",
|
||||||
|
ZError::NOT_FOUND => "NOT_FOUND",
|
||||||
|
ZError::PERMISSION_DENIED => "PERMISSION_DENIED",
|
||||||
|
ZError::NULL_PTR => "NULL_PTR",
|
||||||
|
ZError::EMPTY => "EMPTY",
|
||||||
|
ZError::ALREADY_EXISTS => "ALREADY_EXISTS",
|
||||||
ZError::BUFFER_SIZE => "BUFFER_SIZE",
|
ZError::BUFFER_SIZE => "BUFFER_SIZE",
|
||||||
|
ZError::FAILED_PRECONDITION => "FAILED_PRECONDITION",
|
||||||
ZError::INTERNAL => "INTERNAL",
|
ZError::INTERNAL => "INTERNAL",
|
||||||
ZError::UNIMPLEMENTED => "UNIMPLEMENTED",
|
ZError::UNIMPLEMENTED => "UNIMPLEMENTED",
|
||||||
ZError::INVALID_RESPONSE => "INVALID_RESPONSE",
|
ZError::INVALID_RESPONSE => "INVALID_RESPONSE",
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
use alloc::{
|
||||||
|
string::{String, ToString as _},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use mammoth::zion::ZError;
|
||||||
|
|
||||||
|
pub fn exists(path: &str) -> Result<bool, ZError> {
|
||||||
|
let vfs = crate::get_client();
|
||||||
|
let result = vfs.get_directory(&crate::GetDirectoryRequest {
|
||||||
|
path: path.to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(ZError::NOT_FOUND) => Ok(false),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ls(path: &str) -> Result<Vec<String>, ZError> {
|
||||||
|
let vfs = crate::get_client();
|
||||||
|
let result = vfs.get_directory(&crate::GetDirectoryRequest {
|
||||||
|
path: path.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result.filenames.split(',').map(|s| s.to_string()).collect())
|
||||||
|
}
|
|
@ -1,32 +1,14 @@
|
||||||
use crate::OpenFileRequest;
|
use crate::OpenFileRequest;
|
||||||
use crate::VFSClient;
|
|
||||||
use alloc::string::ToString;
|
use alloc::string::ToString;
|
||||||
use mammoth::zion::ZError;
|
use mammoth::zion::ZError;
|
||||||
|
|
||||||
static mut VFS_CLIENT: Option<VFSClient> = None;
|
|
||||||
|
|
||||||
fn get_client() -> &'static mut VFSClient {
|
|
||||||
unsafe {
|
|
||||||
if let None = VFS_CLIENT {
|
|
||||||
let endpoint_cap = yellowstone::from_init_endpoint()
|
|
||||||
.get_endpoint(&yellowstone::GetEndpointRequest {
|
|
||||||
endpoint_name: "victoriafalls".to_string(),
|
|
||||||
})
|
|
||||||
.expect("Failed to get VFS endpoint");
|
|
||||||
|
|
||||||
VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint));
|
|
||||||
}
|
|
||||||
VFS_CLIENT.as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct File {
|
pub struct File {
|
||||||
memory: mammoth::mem::MemoryRegion,
|
memory: mammoth::mem::MemoryRegion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
pub fn open(path: &str) -> Result<Self, ZError> {
|
pub fn open(path: &str) -> Result<Self, ZError> {
|
||||||
let vfs = get_client();
|
let vfs = crate::get_client();
|
||||||
let resp = vfs.open_file(&OpenFileRequest {
|
let resp = vfs.open_file(&OpenFileRequest {
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
@ -36,7 +18,7 @@ impl File {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn slice(&self, offset: usize, len: usize) -> &[u8] {
|
pub fn slice(&self) -> &[u8] {
|
||||||
&self.memory.slice()[offset..offset + len]
|
self.memory.slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,22 @@ use core::include;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/yunq.rs"));
|
include!(concat!(env!("OUT_DIR"), "/yunq.rs"));
|
||||||
|
|
||||||
|
pub mod dir;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
|
||||||
|
static mut VFS_CLIENT: Option<VFSClient> = None;
|
||||||
|
|
||||||
|
fn get_client() -> &'static mut VFSClient {
|
||||||
|
unsafe {
|
||||||
|
if let None = VFS_CLIENT {
|
||||||
|
let endpoint_cap = yellowstone::from_init_endpoint()
|
||||||
|
.get_endpoint(&yellowstone::GetEndpointRequest {
|
||||||
|
endpoint_name: "victoriafalls".to_string(),
|
||||||
|
})
|
||||||
|
.expect("Failed to get VFS endpoint");
|
||||||
|
|
||||||
|
VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint));
|
||||||
|
}
|
||||||
|
VFS_CLIENT.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,8 +25,7 @@ impl Psf {
|
||||||
pub fn new(path: &str) -> Result<Self, ZError> {
|
pub fn new(path: &str) -> Result<Self, ZError> {
|
||||||
let file = File::open(&path)?;
|
let file = File::open(&path)?;
|
||||||
|
|
||||||
let header = file
|
let header = file.slice()[0..core::mem::size_of::<PsfHeader>()]
|
||||||
.slice(0, core::mem::size_of::<PsfHeader>())
|
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
.cast();
|
.cast();
|
||||||
let psf = Self {
|
let psf = Self {
|
||||||
|
@ -66,7 +65,7 @@ impl Psf {
|
||||||
let offset: usize =
|
let offset: usize =
|
||||||
(self.header.headersize + (index * self.header.bytes_per_glyph)) as usize;
|
(self.header.headersize + (index * self.header.bytes_per_glyph)) as usize;
|
||||||
let len: usize = self.header.bytes_per_glyph as usize;
|
let len: usize = self.header.bytes_per_glyph as usize;
|
||||||
&self.file.slice(offset, len)
|
&self.file.slice()[offset..offset + len]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(&self) -> u32 {
|
pub fn width(&self) -> u32 {
|
||||||
|
|
|
@ -5,6 +5,7 @@ use alloc::{
|
||||||
format,
|
format,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
|
use victoriafalls::dir;
|
||||||
use voyageurs::listener::KeyboardHandler;
|
use voyageurs::listener::KeyboardHandler;
|
||||||
|
|
||||||
pub struct Terminal {
|
pub struct Terminal {
|
||||||
|
@ -84,10 +85,46 @@ impl Terminal {
|
||||||
self.curr_cmd.clear()
|
self.curr_cmd.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_command_parsed(&mut self, cmd: &str, _args: Split<'_, char>) {
|
fn execute_command_parsed(&mut self, cmd: &str, mut args: Split<'_, char>) {
|
||||||
|
// TODO: Check that no extraneous params are provided.
|
||||||
match cmd {
|
match cmd {
|
||||||
"help" => self.write_line("Available commands are 'pwd', 'ls', 'cd', and 'exec'"),
|
"help" => self.write_line("Available commands are 'pwd', 'ls', 'cd', and 'exec'"),
|
||||||
"pwd" => self.write_line(&self.cwd.clone()),
|
"pwd" => self.write_line(&self.cwd.clone()),
|
||||||
|
"cd" => match args.next() {
|
||||||
|
None => self.write_line("Specify a directory"),
|
||||||
|
Some(directory) => match dir::exists(directory) {
|
||||||
|
Ok(true) => self.cwd = directory.to_string(),
|
||||||
|
Ok(false) => self.write_line(&format!("Directory not found: {}", directory)),
|
||||||
|
Err(e) => self.write_line(&format!("Error stating directory {:?}", e)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ls" => {
|
||||||
|
let use_dir = match args.next() {
|
||||||
|
None => self.cwd.clone(),
|
||||||
|
Some(d) => d.to_string(),
|
||||||
|
};
|
||||||
|
match dir::ls(&use_dir) {
|
||||||
|
Err(e) => self.write_line(&format!("Error reading directory {:?}", e)),
|
||||||
|
Ok(files) => {
|
||||||
|
for file in files {
|
||||||
|
self.write_line(&file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"exec" => match args.next() {
|
||||||
|
None => self.write_line("Specify a program"),
|
||||||
|
Some(prog) => {
|
||||||
|
let file = victoriafalls::file::File::open(prog).expect("Failed to open file");
|
||||||
|
let proc_cap = mammoth::elf::spawn_process_from_elf(file.slice())
|
||||||
|
.expect("Faield to spawn process");
|
||||||
|
|
||||||
|
let exit_code = mammoth::syscall::process_wait(proc_cap)
|
||||||
|
.expect("Failed to wait on process.");
|
||||||
|
|
||||||
|
self.write_line(&format!("Process exit code: {}", exit_code));
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => self.write_line(&format!("Unrecognized command: {}", cmd)),
|
_ => self.write_line(&format!("Unrecognized command: {}", cmd)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,46 +8,11 @@ use mammoth::debug;
|
||||||
use mammoth::define_entry;
|
use mammoth::define_entry;
|
||||||
use mammoth::thread;
|
use mammoth::thread;
|
||||||
use mammoth::zion::z_err_t;
|
use mammoth::zion::z_err_t;
|
||||||
use mammoth::zion::ZError;
|
|
||||||
use yellowstone::GetEndpointRequest;
|
use yellowstone::GetEndpointRequest;
|
||||||
use yellowstone::YellowstoneClient;
|
use yellowstone::YellowstoneClient;
|
||||||
use yellowstone::YellowstoneServer;
|
|
||||||
use yunq::server::YunqServer;
|
|
||||||
|
|
||||||
define_entry!();
|
define_entry!();
|
||||||
|
|
||||||
struct YellowstoneImpl {}
|
|
||||||
|
|
||||||
impl yellowstone::YellowstoneServerHandler for YellowstoneImpl {
|
|
||||||
fn register_endpoint(&self, req: &yellowstone::RegisterEndpointRequest) -> Result<(), ZError> {
|
|
||||||
debug!("{}", req.endpoint_name);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_endpoint(&self, req: &GetEndpointRequest) -> Result<yellowstone::Endpoint, ZError> {
|
|
||||||
debug!("{}", req.endpoint_name);
|
|
||||||
Ok(yellowstone::Endpoint {
|
|
||||||
endpoint: unsafe { mammoth::init::SELF_PROC_CAP },
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ahci_info(&self) -> Result<yellowstone::AhciInfo, ZError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_xhci_info(&self) -> Result<yellowstone::XhciInfo, ZError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_framebuffer_info(&self) -> Result<yellowstone::FramebufferInfo, ZError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_denali(&self) -> Result<yellowstone::DenaliInfo, ZError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn main() -> z_err_t {
|
pub extern "C" fn main() -> z_err_t {
|
||||||
debug!("Testing!");
|
debug!("Testing!");
|
||||||
|
@ -72,21 +37,5 @@ pub extern "C" fn main() -> z_err_t {
|
||||||
|
|
||||||
t.join().expect("Failed to wait.");
|
t.join().expect("Failed to wait.");
|
||||||
|
|
||||||
let server = YellowstoneServer::new(YellowstoneImpl {}).expect("Failed to create server");
|
|
||||||
|
|
||||||
let mut yellowstone = YellowstoneClient::new(server.endpoint_cap());
|
|
||||||
|
|
||||||
let t = server.run_server().expect("Failed to start server");
|
|
||||||
|
|
||||||
let endpoint = yellowstone
|
|
||||||
.get_endpoint(&GetEndpointRequest {
|
|
||||||
endpoint_name: "test".to_string(),
|
|
||||||
})
|
|
||||||
.expect("Failed to get endpoint");
|
|
||||||
|
|
||||||
debug!("{:#x}", endpoint.endpoint);
|
|
||||||
|
|
||||||
t.join().expect("Failed to wait");
|
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,15 @@ glcr::ErrorCode MemoryMappingTree::FreeMemoryRange(uint64_t vaddr_base,
|
||||||
}
|
}
|
||||||
auto predecessor_or = mapping_tree_.Predecessor(vaddr_base);
|
auto predecessor_or = mapping_tree_.Predecessor(vaddr_base);
|
||||||
if (predecessor_or && predecessor_or.value().get().vaddr_limit > vaddr_base) {
|
if (predecessor_or && predecessor_or.value().get().vaddr_limit > vaddr_base) {
|
||||||
|
dbgln("Free memory Predecessor check failed: {x} > {x}",
|
||||||
|
predecessor_or.value().get().vaddr_limit, vaddr_base);
|
||||||
return glcr::FAILED_PRECONDITION;
|
return glcr::FAILED_PRECONDITION;
|
||||||
}
|
}
|
||||||
auto last_predecessor_or = mapping_tree_.Predecessor(vaddr_limit);
|
auto last_predecessor_or = mapping_tree_.Predecessor(vaddr_limit);
|
||||||
if (last_predecessor_or &&
|
if (last_predecessor_or &&
|
||||||
last_predecessor_or.value().get().vaddr_limit > vaddr_limit) {
|
last_predecessor_or.value().get().vaddr_limit > vaddr_limit) {
|
||||||
|
dbgln("Free memory Last Predecessor check failed: {x} > {x}",
|
||||||
|
last_predecessor_or.value().get().vaddr_limit, vaddr_limit);
|
||||||
return glcr::FAILED_PRECONDITION;
|
return glcr::FAILED_PRECONDITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,11 @@ void* KernelHeap::Allocate(uint64_t size) {
|
||||||
uint64_t address = next_addr_;
|
uint64_t address = next_addr_;
|
||||||
alloc_count_ += 1;
|
alloc_count_ += 1;
|
||||||
next_addr_ += size;
|
next_addr_ += size;
|
||||||
|
|
||||||
|
// Ensure alingment for these pointers.
|
||||||
|
if (next_addr_ & 0x7) {
|
||||||
|
next_addr_ = (next_addr_ & ~0x7) + 0x8;
|
||||||
|
}
|
||||||
return reinterpret_cast<void*>(address);
|
return reinterpret_cast<void*>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue