Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Feature - Adds MemoryMapping::Identity #460

Merged
merged 1 commit into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,6 @@ mod test {
Executable::jit_compile(&mut executable).unwrap();
}

assert_eq!(10538, executable.mem_size());
assert_eq!(10546, executable.mem_size());
}
}
28 changes: 23 additions & 5 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1014,10 +1014,29 @@ impl<'a, V: Verifier, C: ContextObject> JitCompiler<'a, V, C> {
_ => {}
}

let access_type = if value.is_none() { AccessType::Load } else { AccessType::Store };
let anchor = ANCHOR_TRANSLATE_MEMORY_ADDRESS + len.trailing_zeros() as usize + 4 * (access_type as usize);
self.emit_ins(X86Instruction::push_immediate(OperandSize::S64, self.pc as i32));
self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(anchor, 5)));
if self.config.enable_address_translation {
let access_type = if value.is_none() { AccessType::Load } else { AccessType::Store };
let anchor = ANCHOR_TRANSLATE_MEMORY_ADDRESS + len.trailing_zeros() as usize + 4 * (access_type as usize);
self.emit_ins(X86Instruction::push_immediate(OperandSize::S64, self.pc as i32));
self.emit_ins(X86Instruction::call_immediate(self.relative_to_anchor(anchor, 5)));
} else if value.is_some() {
match len {
1 => self.emit_ins(X86Instruction::store(OperandSize::S8, R10, R11, X86IndirectAccess::Offset(0))),
2 => self.emit_ins(X86Instruction::store(OperandSize::S16, R10, R11, X86IndirectAccess::Offset(0))),
4 => self.emit_ins(X86Instruction::store(OperandSize::S32, R10, R11, X86IndirectAccess::Offset(0))),
8 => self.emit_ins(X86Instruction::store(OperandSize::S64, R10, R11, X86IndirectAccess::Offset(0))),
_ => unreachable!(),
}
} else {
match len {
1 => self.emit_ins(X86Instruction::load(OperandSize::S8, R11, R10, X86IndirectAccess::Offset(0))),
2 => self.emit_ins(X86Instruction::load(OperandSize::S16, R11, R10, X86IndirectAccess::Offset(0))),
4 => self.emit_ins(X86Instruction::load(OperandSize::S32, R11, R10, X86IndirectAccess::Offset(0))),
8 => self.emit_ins(X86Instruction::load(OperandSize::S64, R11, R10, X86IndirectAccess::Offset(0))),
_ => unreachable!(),
}
}

if let Some(dst) = dst {
self.emit_ins(X86Instruction::mov(OperandSize::S64, R11, dst));
}
Expand Down Expand Up @@ -1432,7 +1451,6 @@ impl<'a, V: Verifier, C: ContextObject> JitCompiler<'a, V, C> {
4 => MemoryMapping::load::<u32> as *const u8 as i64,
8 => MemoryMapping::load::<u64> as *const u8 as i64,
_ => unreachable!()

};
self.emit_rust_call(Value::Constant64(load, false), &[
Argument { index: 2, value: Value::Register(R11) }, // Specify first as the src register could be overwritten by other arguments
Expand Down
17 changes: 17 additions & 0 deletions src/memory_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,8 @@ impl<'a> AlignedMemoryMapping<'a> {
/// Maps virtual memory to host memory.
#[derive(Debug)]
pub enum MemoryMapping<'a> {
/// Used when address translation is disabled
Identity,
/// Aligned memory mapping which uses the upper half of an address to
/// identify the underlying memory region.
Aligned(AlignedMemoryMapping<'a>),
Expand All @@ -689,6 +691,10 @@ pub enum MemoryMapping<'a> {
}

impl<'a> MemoryMapping<'a> {
pub(crate) fn new_identity() -> Self {
MemoryMapping::Identity
}

/// Creates a new memory mapping.
///
/// Uses aligned or unaligned memory mapping depending on the value of
Expand Down Expand Up @@ -721,6 +727,7 @@ impl<'a> MemoryMapping<'a> {
/// Map virtual memory to host memory.
pub fn map(&self, access_type: AccessType, vm_addr: u64, len: u64, pc: usize) -> ProgramResult {
match self {
MemoryMapping::Identity => ProgramResult::Ok(vm_addr),
MemoryMapping::Aligned(m) => m.map(access_type, vm_addr, len, pc),
MemoryMapping::Unaligned(m) => m.map(access_type, vm_addr, len, pc),
}
Expand All @@ -732,6 +739,9 @@ impl<'a> MemoryMapping<'a> {
#[inline]
pub fn load<T: Pod + Into<u64>>(&self, vm_addr: u64, pc: usize) -> ProgramResult {
match self {
MemoryMapping::Identity => unsafe {
ProgramResult::Ok(ptr::read_unaligned(vm_addr as *const T).into())
},
MemoryMapping::Aligned(m) => m.load::<T>(vm_addr, pc),
MemoryMapping::Unaligned(m) => m.load::<T>(vm_addr, pc),
}
Expand All @@ -743,6 +753,10 @@ impl<'a> MemoryMapping<'a> {
#[inline]
pub fn store<T: Pod>(&self, value: T, vm_addr: u64, pc: usize) -> ProgramResult {
match self {
MemoryMapping::Identity => unsafe {
ptr::write_unaligned(vm_addr as *mut T, value);
ProgramResult::Ok(0)
},
MemoryMapping::Aligned(m) => m.store(value, vm_addr, pc),
MemoryMapping::Unaligned(m) => m.store(value, vm_addr, pc),
}
Expand All @@ -755,6 +769,7 @@ impl<'a> MemoryMapping<'a> {
vm_addr: u64,
) -> Result<&MemoryRegion, Box<dyn std::error::Error>> {
match self {
MemoryMapping::Identity => Err(Box::new(EbpfError::InvalidMemoryRegion(0))),
MemoryMapping::Aligned(m) => m.region(access_type, vm_addr),
MemoryMapping::Unaligned(m) => m.region(access_type, vm_addr),
}
Expand All @@ -763,6 +778,7 @@ impl<'a> MemoryMapping<'a> {
/// Returns the `MemoryRegion`s in this mapping.
pub fn get_regions(&self) -> &[MemoryRegion] {
match self {
MemoryMapping::Identity => &[],
MemoryMapping::Aligned(m) => m.get_regions(),
MemoryMapping::Unaligned(m) => m.get_regions(),
}
Expand All @@ -771,6 +787,7 @@ impl<'a> MemoryMapping<'a> {
/// Replaces the `MemoryRegion` at the given index
pub fn replace_region(&mut self, index: usize, region: MemoryRegion) -> Result<(), EbpfError> {
match self {
MemoryMapping::Identity => Err(EbpfError::InvalidMemoryRegion(index)),
MemoryMapping::Aligned(m) => m.replace_region(index, region),
MemoryMapping::Unaligned(m) => m.replace_region(index, region),
}
Expand Down
8 changes: 7 additions & 1 deletion src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ pub struct Config {
pub max_call_depth: usize,
/// Size of a stack frame in bytes, must match the size specified in the LLVM BPF backend
pub stack_frame_size: usize,
/// Enables the use of MemoryMapping and MemoryRegion for address translation
pub enable_address_translation: bool,
/// Enables gaps in VM address space between the stack frames
pub enable_stack_frame_gaps: bool,
/// Maximal pc distance after which a new instruction meter validation is emitted by the JIT
Expand Down Expand Up @@ -255,6 +257,7 @@ impl Default for Config {
Self {
max_call_depth: 20,
stack_frame_size: 4_096,
enable_address_translation: true,
enable_stack_frame_gaps: true,
instruction_meter_checkpoint_distance: 10000,
enable_instruction_meter: true,
Expand Down Expand Up @@ -500,7 +503,7 @@ impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> {
pub fn new(
executable: &'a Executable<V, C>,
context_object: &'a mut C,
memory_mapping: MemoryMapping<'a>,
mut memory_mapping: MemoryMapping<'a>,
stack_len: usize,
) -> EbpfVm<'a, V, C> {
let config = executable.get_config();
Expand All @@ -511,6 +514,9 @@ impl<'a, V: Verifier, C: ContextObject> EbpfVm<'a, V, C> {
// within a frame the stack grows down, but frames are ascending
config.stack_frame_size
} as u64);
if !config.enable_address_translation {
memory_mapping = MemoryMapping::new_identity();
}
EbpfVm {
executable,
#[cfg(feature = "debugger")]
Expand Down