//! 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}, log::{debug, error, info, trace}, }; pub fn handler(vm: &mut Vm) { let ecall_number = vm.registers[2].cast::(); // debug!("Ecall number {:?}", ecall_number); //info!("Register dump: {:?}", vm.registers); 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].cast::() { 0 => false, 1 => true, _ => { panic!("Bad"); } }; let length = vm.registers[4].cast::(); let mut buffs = IPC_BUFFERS.lock(); let abc; match bounded { false => { abc = IpcBuffer::new(false, 0); } true => { abc = IpcBuffer::new(true, length); } }; let buff_id = arch::hardware_random_u64(); buffs.insert(buff_id, abc); 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); use alloc::vec::Vec; 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(not(target_arch = "x86_64"))] 3 => info!("TODO: implement whatever buffer 3 does for no x86_64"), #[cfg(target_arch = "x86_64")] 3 => { unsafe fn x86_out( address: u16, value: T, ) { x86_64::instructions::port::Port::new(address).write(value); } unsafe fn x86_in(address: u16) -> T { x86_64::instructions::port::Port::new(address).read() } let msg_vec = block_read(mem_addr, length); let msg_type = msg_vec[0]; match msg_type { 0 => 'wow: { let size = match msg_vec[0] { 0 => 1, 1 => 2, 2 => 4, _ => { error!("Tried to write more than 32 bits"); break 'wow; } }; let addr = u16::from_le_bytes(msg_vec[1..3].try_into().unwrap()); let value = unsafe { match size { 1 => x86_in::(addr) as u64, 2 => x86_in::(addr) as u64, 4 => x86_in::(addr) as u64, _ => panic!("how?"), } }; trace!("Read the value {} from address {}", value, addr); vm.registers[1] = hbvm::value::Value(value); } 1 => 'wow: { let size = match msg_vec[1] { 0 => 1, 1 => 2, 2 => 4, _ => { error!("Tried to write more than 32 bits"); break 'wow; } }; let addr = unsafe { u16::from_le_bytes(msg_vec[1..3].try_into().unwrap_unchecked()) }; trace!("Setting address {}", addr); unsafe { match size { 1 => x86_out(addr, msg_vec[3]), 2 => x86_out( addr, u16::from_le_bytes( msg_vec[3..5].try_into().unwrap_unchecked(), ), ), 4 => x86_out( addr, u32::from_le_bytes( msg_vec[3..7].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 => { // limit to last 32 bits vm.registers[1] = hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF); } 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 mut msg_vec = Vec::with_capacity(length); for x in 0..(length as isize) { let xyz = mem_addr as *const u8; let value = unsafe { xyz.offset(x).read() }; msg_vec.push(value); } debug!( "Message {:?} has been sent to Buffer({})", msg_vec, buffer_id ); buff.push(msg_vec); } None => { log::error!("Access of non-existent buffer {}", buffer_id) } } drop(buffs); } } } 4 => { let buffer_id = vm.registers[3].cast::(); let mut map_ptr = vm.registers[4].cast::(); let max_length = vm.registers[5].cast::(); let mut buffs = IPC_BUFFERS.lock(); let buff: &mut IpcBuffer; if buffs.get_mut(&buffer_id).is_some() { buff = buffs.get_mut(&buffer_id).unwrap(); } else { // info!("AHHH"); vm.registers[1] = hbvm::value::Value(0); return; } let pop = buff.pop(); if pop.is_err() { return; } let msg = pop.unwrap(); if msg.len() > max_length.try_into().unwrap() { info!("{}", max_length); error!("Message is too long to map in."); } else { unsafe { let ptr: *mut u64 = &mut map_ptr; for (index, byte) in msg.iter().enumerate() { ptr.offset(index.try_into().unwrap()).write_bytes(*byte, 1); } } debug!("Recieve {:?} from Buffer({})", msg, buffer_id); } } 5 => { #[cfg(target_arch = "x86_64")] { let r2 = vm.registers[2].cast::(); unsafe fn x86_in(address: u16) -> u32 { x86_64::instructions::port::Port::new(address).read() } unsafe fn x86_out(address: u16, value: u32) { x86_64::instructions::port::Port::new(address).write(value); } 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, } // use {alloc::vec, log::Record}; // fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { // let mut val = alloc::vec::Vec::new(); // for _ in 0..4096 { // val.push(0); // } // info!("Block address: {:?}", val.as_ptr()); // vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64); // vm.registers[2] = hbvm::value::Value(4096); // Ok(()) // }