use isr_macros::Field;
use zerocopy::{FromBytes, Immutable, IntoBytes};
use super::session::VmiSession;
use crate::{
AccessContext, AddressContext, Architecture, Pa, Registers as _, Va, VcpuId, VmiCore, VmiError,
VmiRead, VmiWrite,
driver::VmiSetRegisters,
os::{NoOS, VmiOs},
};
pub struct VmiState<'a, Os>
where
Os: VmiOs,
{
session: VmiSession<'a, Os>,
registers: &'a <Os::Architecture as Architecture>::Registers,
}
impl<Os> Clone for VmiState<'_, Os>
where
Os: VmiOs,
{
fn clone(&self) -> Self {
*self
}
}
impl<Os> Copy for VmiState<'_, Os> where Os: VmiOs {}
impl<'a, Os> std::ops::Deref for VmiState<'a, Os>
where
Os: VmiOs,
{
type Target = VmiSession<'a, Os>;
fn deref(&self) -> &Self::Target {
&self.session
}
}
impl<'a, Os> VmiState<'a, Os>
where
Os: VmiOs,
{
pub fn new(
session: &'a VmiSession<'a, Os>,
registers: &'a <Os::Architecture as Architecture>::Registers,
) -> Self {
Self {
session: *session,
registers,
}
}
pub fn with_registers(
&'a self,
registers: &'a <Os::Architecture as Architecture>::Registers,
) -> Self {
Self {
session: self.session,
registers,
}
}
pub fn without_os(&self) -> VmiState<'a, NoOS<Os::Driver>> {
VmiState {
session: self.session.without_os(),
registers: self.registers,
}
}
pub fn session(&self) -> &VmiSession<'a, Os> {
&self.session
}
pub fn registers(&self) -> &'a <Os::Architecture as Architecture>::Registers {
self.registers
}
pub fn os(&self) -> VmiOsState<'a, Os> {
VmiOsState(*self)
}
pub fn access_context(&self, address: Va) -> AccessContext {
self.registers().access_context(address)
}
pub fn address_context(&self, address: Va) -> AddressContext {
self.registers().address_context(address)
}
pub fn translation_root(&self, va: Va) -> Pa {
self.registers().translation_root(va)
}
}
impl<'a, Os> VmiState<'a, Os>
where
Os: VmiOs,
Os::Driver: VmiRead,
{
pub fn return_address(&self) -> Result<Va, VmiError> {
self.registers().return_address(self.core())
}
pub fn translate_address(&self, va: Va) -> Result<Pa, VmiError> {
self.core().translate_address(self.address_context(va))
}
pub fn read(&self, address: Va, buffer: &mut [u8]) -> Result<(), VmiError> {
self.read_in(self.access_context(address), buffer)
}
pub fn read_u8(&self, address: Va) -> Result<u8, VmiError> {
self.read_u8_in(self.access_context(address))
}
pub fn read_u16(&self, address: Va) -> Result<u16, VmiError> {
self.read_u16_in(self.access_context(address))
}
pub fn read_u32(&self, address: Va) -> Result<u32, VmiError> {
self.read_u32_in(self.access_context(address))
}
pub fn read_u64(&self, address: Va) -> Result<u64, VmiError> {
self.read_u64_in(self.access_context(address))
}
pub fn read_uint(&self, address: Va, size: usize) -> Result<u64, VmiError> {
self.read_uint_in(self.access_context(address), size)
}
pub fn read_field(&self, base_address: Va, field: &Field) -> Result<u64, VmiError> {
self.read_field_in(self.access_context(base_address), field)
}
pub fn read_address(&self, address: Va) -> Result<u64, VmiError> {
self.read_address_in(self.access_context(address))
}
pub fn read_address_native(&self, address: Va) -> Result<u64, VmiError> {
self.read_address_native_in(self.access_context(address))
}
pub fn read_address32(&self, address: Va) -> Result<u64, VmiError> {
self.read_address32_in(self.access_context(address))
}
pub fn read_address64(&self, address: Va) -> Result<u64, VmiError> {
self.read_address64_in(self.access_context(address))
}
pub fn read_va(&self, address: Va) -> Result<Va, VmiError> {
self.read_va_in(self.access_context(address))
}
pub fn read_va_native(&self, address: Va) -> Result<Va, VmiError> {
self.read_va_native_in(self.access_context(address))
}
pub fn read_va32(&self, address: Va) -> Result<Va, VmiError> {
self.read_va32_in(self.access_context(address))
}
pub fn read_va64(&self, address: Va) -> Result<Va, VmiError> {
self.read_va64_in(self.access_context(address))
}
pub fn read_string_bytes_limited(
&self,
address: Va,
limit: usize,
) -> Result<Vec<u8>, VmiError> {
self.read_string_bytes_limited_in(self.access_context(address), limit)
}
pub fn read_string_bytes(&self, address: Va) -> Result<Vec<u8>, VmiError> {
self.read_string_bytes_in(self.access_context(address))
}
pub fn read_string_utf16_bytes_limited(
&self,
address: Va,
limit: usize,
) -> Result<Vec<u16>, VmiError> {
self.read_string_utf16_bytes_limited_in(self.access_context(address), limit)
}
pub fn read_string_utf16_bytes(&self, address: Va) -> Result<Vec<u16>, VmiError> {
self.read_string_utf16_bytes_in(self.access_context(address))
}
pub fn read_string_limited(&self, address: Va, limit: usize) -> Result<String, VmiError> {
self.read_string_limited_in(self.access_context(address), limit)
}
pub fn read_string(&self, address: Va) -> Result<String, VmiError> {
self.read_string_in(self.access_context(address))
}
pub fn read_string_utf16_limited(&self, address: Va, limit: usize) -> Result<String, VmiError> {
self.read_string_utf16_limited_in(self.access_context(address), limit)
}
pub fn read_string_utf16(&self, address: Va) -> Result<String, VmiError> {
self.read_string_utf16_in(self.access_context(address))
}
pub fn read_struct<T>(&self, address: Va) -> Result<T, VmiError>
where
T: IntoBytes + FromBytes,
{
self.read_struct_in(self.access_context(address))
}
pub fn read_in(
&self,
ctx: impl Into<AccessContext>,
buffer: &mut [u8],
) -> Result<(), VmiError> {
self.core().read(ctx, buffer)
}
pub fn read_u8_in(&self, ctx: impl Into<AccessContext>) -> Result<u8, VmiError> {
self.core().read_u8(ctx)
}
pub fn read_u16_in(&self, ctx: impl Into<AccessContext>) -> Result<u16, VmiError> {
self.core().read_u16(ctx)
}
pub fn read_u32_in(&self, ctx: impl Into<AccessContext>) -> Result<u32, VmiError> {
self.core().read_u32(ctx)
}
pub fn read_u64_in(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError> {
self.core().read_u64(ctx)
}
pub fn read_uint_in(
&self,
ctx: impl Into<AccessContext>,
size: usize,
) -> Result<u64, VmiError> {
self.core().read_uint(ctx, size)
}
pub fn read_field_in(
&self,
ctx: impl Into<AccessContext>,
field: &Field,
) -> Result<u64, VmiError> {
self.core().read_field(ctx, field)
}
pub fn read_address_in(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError> {
self.core()
.read_address(ctx, self.registers().effective_address_width())
}
pub fn read_address_native_in(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError> {
self.core()
.read_address(ctx, self.registers().address_width())
}
pub fn read_address32_in(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError> {
self.core().read_address32(ctx)
}
pub fn read_address64_in(&self, ctx: impl Into<AccessContext>) -> Result<u64, VmiError> {
self.core().read_address64(ctx)
}
pub fn read_va_in(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError> {
self.core()
.read_va(ctx, self.registers().effective_address_width())
}
pub fn read_va_native_in(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError> {
self.core().read_va(ctx, self.registers().address_width())
}
pub fn read_va32_in(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError> {
self.core().read_va32(ctx)
}
pub fn read_va64_in(&self, ctx: impl Into<AccessContext>) -> Result<Va, VmiError> {
self.core().read_va64(ctx)
}
pub fn read_string_bytes_limited_in(
&self,
ctx: impl Into<AccessContext>,
limit: usize,
) -> Result<Vec<u8>, VmiError> {
self.core().read_string_bytes_limited(ctx, limit)
}
pub fn read_string_bytes_in(&self, ctx: impl Into<AccessContext>) -> Result<Vec<u8>, VmiError> {
self.core().read_string_bytes(ctx)
}
pub fn read_string_utf16_bytes_limited_in(
&self,
ctx: impl Into<AccessContext>,
limit: usize,
) -> Result<Vec<u16>, VmiError> {
self.core().read_string_utf16_bytes_limited(ctx, limit)
}
pub fn read_string_utf16_bytes_in(
&self,
ctx: impl Into<AccessContext>,
) -> Result<Vec<u16>, VmiError> {
self.core().read_string_utf16_bytes(ctx)
}
pub fn read_string_limited_in(
&self,
ctx: impl Into<AccessContext>,
limit: usize,
) -> Result<String, VmiError> {
self.core().read_string_limited(ctx, limit)
}
pub fn read_string_in(&self, ctx: impl Into<AccessContext>) -> Result<String, VmiError> {
self.core().read_string(ctx)
}
pub fn read_string_utf16_limited_in(
&self,
ctx: impl Into<AccessContext>,
limit: usize,
) -> Result<String, VmiError> {
self.core().read_string_utf16_limited(ctx, limit)
}
pub fn read_string_utf16_in(&self, ctx: impl Into<AccessContext>) -> Result<String, VmiError> {
self.core().read_string_utf16(ctx)
}
pub fn read_struct_in<T>(&self, ctx: impl Into<AccessContext>) -> Result<T, VmiError>
where
T: IntoBytes + FromBytes,
{
self.core().read_struct(ctx)
}
}
impl<'a, Os> VmiState<'a, Os>
where
Os: VmiOs,
Os::Driver: VmiRead + VmiWrite,
{
pub fn write(&self, address: Va, buffer: &[u8]) -> Result<(), VmiError> {
self.write_in(self.access_context(address), buffer)
}
pub fn write_in(&self, ctx: impl Into<AccessContext>, buffer: &[u8]) -> Result<(), VmiError> {
self.core().write(ctx, buffer)
}
pub fn write_u8(&self, address: Va, value: u8) -> Result<(), VmiError> {
self.core().write_u8(self.access_context(address), value)
}
pub fn write_u16(&self, address: Va, value: u16) -> Result<(), VmiError> {
self.core().write_u16(self.access_context(address), value)
}
pub fn write_u32(&self, address: Va, value: u32) -> Result<(), VmiError> {
self.core().write_u32(self.access_context(address), value)
}
pub fn write_u64(&self, address: Va, value: u64) -> Result<(), VmiError> {
self.core().write_u64(self.access_context(address), value)
}
pub fn write_struct<T>(&self, address: Va, value: T) -> Result<(), VmiError>
where
T: FromBytes + IntoBytes + Immutable,
{
self.core()
.write_struct(self.access_context(address), value)
}
}
impl<'a, Os> VmiState<'a, Os>
where
Os: VmiOs,
Os::Driver: VmiSetRegisters,
{
pub fn set_registers(
&self,
vcpu: VcpuId,
registers: <Os::Architecture as Architecture>::Registers,
) -> Result<(), VmiError> {
self.core().set_registers(vcpu, registers)
}
}
pub struct VmiOsState<'a, Os>(VmiState<'a, Os>)
where
Os: VmiOs;
impl<'a, Os> VmiOsState<'a, Os>
where
Os: VmiOs,
{
pub fn core(&self) -> &'a VmiCore<Os::Driver> {
self.0.core()
}
pub fn underlying_os(&self) -> &'a Os {
self.0.underlying_os()
}
pub fn session(&self) -> &VmiSession<'a, Os> {
self.0.session()
}
pub fn state(&self) -> VmiState<'a, Os> {
self.0
}
pub fn registers(&self) -> &<Os::Architecture as Architecture>::Registers {
self.0.registers()
}
pub fn function_argument_for_registers(
&self,
registers: &<Os::Architecture as Architecture>::Registers,
index: u64,
) -> Result<u64, VmiError> {
Os::function_argument(self.0.with_registers(registers), index)
}
pub fn function_return_value_for_registers(
&self,
registers: &<Os::Architecture as Architecture>::Registers,
) -> Result<u64, VmiError> {
Os::function_return_value(self.0.with_registers(registers))
}
}