forked from AbleOS/ableos
257 lines
9.7 KiB
Rust
257 lines
9.7 KiB
Rust
//! Environment call handling routines
|
|
|
|
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
|
|
|
|
use crate::{
|
|
holeybytes::{
|
|
kernel_services::{
|
|
block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler,
|
|
service_definition_service::sds_msg_handler,
|
|
},
|
|
ExecThread,
|
|
},
|
|
kmain::EXECUTOR,
|
|
task::Executor,
|
|
};
|
|
|
|
use {
|
|
super::Vm,
|
|
crate::{arch, ipc::buffer::IpcBuffer, kmain::IPC_BUFFERS},
|
|
hbvm::value::Value,
|
|
log::{debug, error, info, trace},
|
|
};
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[inline(always)]
|
|
unsafe fn x86_out<T: x86_64::instructions::port::PortWrite>(address: u16, value: T) {
|
|
x86_64::instructions::port::Port::new(address).write(value);
|
|
}
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[inline(always)]
|
|
unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
|
|
x86_64::instructions::port::Port::new(address).read()
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub fn handler(vm: &mut Vm) {
|
|
let ecall_number = vm.registers[2].cast::<u64>();
|
|
|
|
match ecall_number {
|
|
0 => {
|
|
// TODO: explode computer
|
|
// hello world ecall
|
|
for x in 0u64..=255 {
|
|
vm.registers[x as usize] = x.into();
|
|
}
|
|
}
|
|
1 => {
|
|
// Make buffer
|
|
|
|
let bounded = match vm.registers[3] {
|
|
Value(0) => false,
|
|
Value(1) => true,
|
|
_ => {
|
|
panic!("Bad");
|
|
}
|
|
};
|
|
|
|
let length = vm.registers[4].cast::<u64>();
|
|
|
|
let mut buffs = IPC_BUFFERS.lock();
|
|
|
|
let buff_id = arch::hardware_random_u64();
|
|
buffs.insert(
|
|
buff_id,
|
|
match bounded {
|
|
false => IpcBuffer::new(false, 0),
|
|
true => IpcBuffer::new(true, length),
|
|
},
|
|
);
|
|
vm.registers[1] = hbvm::value::Value(buff_id);
|
|
}
|
|
2 => {
|
|
log::error!("Oops, deleting buffers is not implemented.")
|
|
// Delete buffer
|
|
}
|
|
3 => {
|
|
// Send a message to a buffer
|
|
let buffer_id = vm.registers[3].cast::<u64>();
|
|
let mem_addr = vm.registers[4].cast::<u64>();
|
|
let length = vm.registers[5].cast::<u64>() as usize;
|
|
trace!("IPC address: {:?}", mem_addr);
|
|
|
|
match buffer_id {
|
|
0 => match sds_msg_handler(vm, mem_addr, length) {
|
|
Ok(()) => {}
|
|
Err(err) => log::error!("Improper sds format: {err:?}"),
|
|
},
|
|
1 => match log_msg_handler(vm, mem_addr, length) {
|
|
Ok(()) => {}
|
|
Err(_) => log::error!("Improper log format"),
|
|
},
|
|
2 => {
|
|
use crate::holeybytes::kernel_services::mem_serve::memory_msg_handler;
|
|
match memory_msg_handler(vm, mem_addr, length) {
|
|
Ok(_) => {}
|
|
Err(_) => {}
|
|
}
|
|
}
|
|
#[cfg(target_arch = "x86_64")]
|
|
3 => {
|
|
let msg_vec = block_read(mem_addr, length);
|
|
let msg_type = msg_vec[0];
|
|
match msg_type {
|
|
0 => unsafe {
|
|
let size = msg_vec[1];
|
|
let addr =
|
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
|
let value = match size {
|
|
0 => x86_in::<u8>(addr) as u64,
|
|
1 => x86_in::<u16>(addr) as u64,
|
|
2 => x86_in::<u32>(addr) as u64,
|
|
_ => panic!("Trying to read size other than: 8, 16, 32 from port."),
|
|
};
|
|
// info!("Read the value {} from address {}", value, addr);
|
|
vm.registers[1] = hbvm::value::Value(value);
|
|
},
|
|
1 => unsafe {
|
|
let size = msg_vec[1];
|
|
let addr =
|
|
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
|
|
// info!("Setting address {}", addr);
|
|
|
|
match size {
|
|
0 => x86_out(addr, msg_vec[4]),
|
|
1 => x86_out(
|
|
addr,
|
|
u16::from_le_bytes(msg_vec[4..6].try_into().unwrap_unchecked()),
|
|
),
|
|
2 => x86_out(
|
|
addr,
|
|
u32::from_le_bytes(msg_vec[4..8].try_into().unwrap_unchecked()),
|
|
),
|
|
_ => panic!("How?"),
|
|
}
|
|
},
|
|
_ => {}
|
|
}
|
|
}
|
|
#[cfg(not(target_arch = "x86_64"))]
|
|
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
|
|
// source of rng
|
|
4 => {
|
|
let block = block_read(mem_addr, length);
|
|
block.chunks_mut(8.min(length)).for_each(|chunk| {
|
|
chunk.clone_from_slice(
|
|
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
|
|
);
|
|
});
|
|
vm.registers[1] = hbvm::value::Value(mem_addr);
|
|
}
|
|
5 => match dt_msg_handler(vm, mem_addr, length) {
|
|
Ok(()) => {}
|
|
Err(_) => log::error!("Improper dt query"),
|
|
},
|
|
6 => unsafe {
|
|
let program = block_read(mem_addr, length);
|
|
|
|
// decode AbleOS Executable format
|
|
let header = &program[0..46];
|
|
let magic_slice = &header[0..3];
|
|
if magic_slice != [0x15, 0x91, 0xD2] {
|
|
log::error!("Invalid magic number at the start of executable.");
|
|
return;
|
|
}
|
|
|
|
let executable_format_version =
|
|
u32::from_le_bytes(header[3..7].try_into().unwrap());
|
|
let offset = if executable_format_version == 0 {
|
|
47
|
|
} else {
|
|
error!("Invalid executable format.");
|
|
return;
|
|
};
|
|
|
|
let code_length = u64::from_le_bytes(header[7..15].try_into().unwrap());
|
|
let data_length = u64::from_le_bytes(header[15..23].try_into().unwrap());
|
|
let end = (code_length + data_length) as usize;
|
|
log::debug!("{code_length} + {data_length} = {end}");
|
|
|
|
let thr = ExecThread::new(&program[offset..end], Address::new(0));
|
|
vm.registers[1] = Value(
|
|
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
|
|
.unwrap()
|
|
.spawn(Box::pin(async move {
|
|
if let Err(e) = thr.await {
|
|
log::error!("{e:?}");
|
|
}
|
|
})) as u64,
|
|
);
|
|
log::debug!("spawned a process");
|
|
},
|
|
|
|
buffer_id => {
|
|
let mut buffs = IPC_BUFFERS.lock();
|
|
match buffs.get_mut(&buffer_id) {
|
|
Some(buff) => {
|
|
let msg_vec = block_read(mem_addr, length);
|
|
buff.push(msg_vec.to_vec());
|
|
debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer_id);
|
|
}
|
|
None => {
|
|
log::error!("Access of non-existent buffer {}", buffer_id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
4 => {
|
|
let buffer_id = vm.registers[3].cast::<u64>();
|
|
let map_ptr = vm.registers[4].cast::<u64>();
|
|
let max_length = vm.registers[5].cast::<u64>();
|
|
|
|
let mut buffs = IPC_BUFFERS.lock();
|
|
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
|
|
Some(buff) => buff,
|
|
None => panic!(
|
|
"Failed to get buffer: id={buffer_id}, ptr={map_ptr}, length={max_length}"
|
|
),
|
|
};
|
|
|
|
let msg = match buff.pop() {
|
|
Ok(msg) => msg,
|
|
Err(_) => return,
|
|
};
|
|
if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
|
|
info!("{}", max_length);
|
|
error!("Message is too long to map in.");
|
|
} else {
|
|
unsafe {
|
|
let ptr = map_ptr as *mut u8;
|
|
ptr.copy_from_nonoverlapping(msg.as_ptr(), msg.len());
|
|
}
|
|
|
|
debug!("Recieve {:?} from Buffer({})", msg, buffer_id);
|
|
}
|
|
}
|
|
5 => {
|
|
#[cfg(target_arch = "x86_64")]
|
|
{
|
|
let r2 = vm.registers[2].cast::<u64>();
|
|
let x = hbvm::value::Value(unsafe { x86_in::<u8>(r2 as u16) } as u64);
|
|
// info!("Read {:?} from Port {:?}", x, r2);
|
|
vm.registers[3] = x
|
|
}
|
|
}
|
|
_ => {
|
|
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum LogError {
|
|
NoMessages,
|
|
InvalidLogFormat,
|
|
}
|