//! Environment call handling routines use crate::holeybytes::kernel_services::{ block_read, dt_msg_handler::dt_msg_handler, logging_service::log_msg_handler, service_definition_service::sds_msg_handler, }; 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(address: u16, value: T) { x86_64::instructions::port::Port::new(address).write(value); } #[cfg(target_arch = "x86_64")] #[inline(always)] unsafe fn x86_in(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::(); 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::(); 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), }, ); info!("Buffer ID: {}", buff_id); vm.registers[1] = hbvm::value::Value(buff_id); } 2 => { // Delete buffer } 3 => { // Send a message to a buffer let buffer_id = vm.registers[3].cast::(); let mem_addr = vm.registers[4].cast::(); let length = vm.registers[5].cast::() 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::(addr) as u64, 1 => x86_in::(addr) as u64, 2 => x86_in::(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"), }, 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::(); let map_ptr = vm.registers[4].cast::(); let max_length = vm.registers[5].cast::(); 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(msg.as_ptr(), msg.len()); } debug!("Recieve {:?} from Buffer({})", msg, buffer_id); } } 5 => { #[cfg(target_arch = "x86_64")] { let r2 = vm.registers[2].cast::(); let x = hbvm::value::Value(unsafe { x86_in::(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, }