use arcbox_hv::reg::{HV_REG_X1 as X1, HV_REG_X2 as X2, HV_REG_X3 as X3, HV_REG_X4 as X4};
pub const ARCBOX_HVC_PROBE: u64 = 0xC200_0000;
pub const ARCBOX_HVC_BLK_READ: u64 = 0xC200_0001;
pub const ARCBOX_HVC_BLK_WRITE: u64 = 0xC200_0002;
pub const ARCBOX_HVC_BLK_FLUSH: u64 = 0xC200_0003;
pub fn handle_hvc_blk_io(
vcpu: &arcbox_hv::HvVcpu,
hvc_blk_fds: &[(i32, u32)],
device_manager: &crate::device::DeviceManager,
is_write: bool,
) -> u64 {
let Ok(device_idx) = vcpu.get_reg(X1) else {
return (-libc::EINVAL as i64) as u64;
};
let Ok(sector) = vcpu.get_reg(X2) else {
return (-libc::EINVAL as i64) as u64;
};
let Ok(buffer_gpa) = vcpu.get_reg(X3) else {
return (-libc::EINVAL as i64) as u64;
};
let Ok(byte_len) = vcpu.get_reg(X4) else {
return (-libc::EINVAL as i64) as u64;
};
let byte_len = byte_len as usize;
if byte_len == 0 {
return (-libc::EINVAL as i64) as u64;
}
let Some(&(raw_fd, blk_size)) = hvc_blk_fds.get(device_idx as usize) else {
return (-libc::ENODEV as i64) as u64;
};
let Some(ram_base) = device_manager.guest_ram_base_ptr() else {
return (-libc::EFAULT as i64) as u64;
};
let gpa_base = device_manager.guest_ram_gpa() as usize;
let ram_size = device_manager.guest_ram_size();
let gpa = buffer_gpa as usize;
if gpa < gpa_base
|| gpa
.checked_add(byte_len)
.is_none_or(|end| end > gpa_base + ram_size)
{
return (-libc::EFAULT as i64) as u64;
}
let host_ptr = unsafe { ram_base.add(gpa - gpa_base) };
let Some(byte_offset) = sector.checked_mul(u64::from(blk_size)) else {
return (-libc::EINVAL as i64) as u64;
};
#[allow(clippy::cast_possible_wrap)]
let offset = byte_offset as libc::off_t;
let n = if is_write {
unsafe { libc::pwrite(raw_fd, host_ptr.cast(), byte_len, offset) }
} else {
unsafe { libc::pread(raw_fd, host_ptr.cast(), byte_len, offset) }
};
if n < 0 {
let errno = std::io::Error::last_os_error()
.raw_os_error()
.unwrap_or(libc::EIO);
return (-errno as i64) as u64;
}
n as u64
}
pub fn handle_hvc_blk_flush(vcpu: &arcbox_hv::HvVcpu, hvc_blk_fds: &[(i32, u32)]) -> u64 {
let Ok(device_idx) = vcpu.get_reg(X1) else {
return (-libc::EINVAL as i64) as u64;
};
let Some(&(raw_fd, _)) = hvc_blk_fds.get(device_idx as usize) else {
return (-libc::ENODEV as i64) as u64;
};
let ret = unsafe { libc::fsync(raw_fd) };
if ret < 0 {
let errno = std::io::Error::last_os_error()
.raw_os_error()
.unwrap_or(libc::EIO);
return (-errno as i64) as u64;
}
0
}