use core::mem::MaybeUninit; use log::error; use peer_id::Uuid; use rust_support::mmu::ArchMmuFlags; use rust_support::paddr_t; use rust_support::status_t; use rust_support::Error as LkError; use zerocopy::FromZeros;
pubusecrate::sys::arm_ffa_partition_info_get_count; pubusecrate::sys::arm_ffa_partition_info_get_desc; pubusecrate::sys::ffa_part_info_desc as FFAPartInfoDesc;
// bindgen'ed as u32; exposing this as a usize avoids casts in many places pubconst ARM_FFA_MSG_EXTENDED_ARGS_COUNT: usize = crate::sys::ARM_FFA_MSG_EXTENDED_ARGS_COUNT as usize;
pubusecrate::sys::FFA_PAGE_SIZE;
mod sys { #![allow(unused)] #![allow(non_camel_case_types)] use peer_id::uuid_t;
include!(env!("BINDGEN_INC_FILE"));
}
pubtype EndpointID = u16;
/// An FFA memory handle that has been shared with an endpoint. /// /// The caller must call `mem_reclaim` on memory handles to avoid leaking memory to other FFA /// endpoints. #[derive(Debug)] pubstruct MemoryHandle(u64);
impl MemoryHandle { /// Get the value of the FFA memory handle. pubfn get(&self) -> u64 { // This can be safe because mem_reclaim accepts `Self` instead of `u64` and freeing through // C's arm_ffa_mem_reclaim will require unsafe anyway. self.0
}
}
pubfn get_init_state() -> FFAInitState { // SAFETY: This function only reads a static which is only written to once during an LK init // hook. LK init hooks run sequentially so it has no safety requirements to avoid data races // when reading from this variable. let init_state = unsafe { arm_ffa_get_init_state() }; match init_state {
arm_ffa_init_state::ARM_FFA_INIT_FAILED => FFAInitState::InitFailed,
arm_ffa_init_state::ARM_FFA_INIT_UNINIT => FFAInitState::Uninit,
arm_ffa_init_state::ARM_FFA_INIT_SUCCESS => { // SAFETY: This function reads a static which is only written to once during an LK init // hook. LK init hooks run sequentially so it has no safety requirements to avoid data // races when reading from this variable. We also ensured that arm_ffa_get_init_state // returned success to avoid triggering an assert in this function. let version = unsafe { arm_ffa_get_version() }; let major_version = (version >> 16) as u16; let minor_version = (version & 0xFFFF) as u16;
FFAInitState::InitSuccess { major_version, minor_version }
}
}
}
/// Register a callback for a given FFA endpoint service. /// /// The handler is called every time an FFA_MSG_SEND_DIRECT_REQ2 with the given UUID is received. /// The handler takes the sender VM ID and the DIRECT_REQ2 params as arguments. The pointee is then /// returned to the FFA endpoint as the response parameters in FFA_MSG_SEND_DIRECT_RESP2. /// /// # Safety /// /// The callback passed to this function is allowed to treat its params pointer argument as a /// mutable reference to a 14-element u64 array, but must not have any other safety requirements. pubunsafefn register_direct_req2_handler(
endpoint_service: Uuid,
handler: unsafeextern"C"fn(u16, *mut u64) -> status_t,
) -> Result<(), LkError> { // SAFETY: This schedules calling the unsafe handler function at a later point. Registering // the handler itself is thread-safe since arm_ffa_register_direct_req2_handler grabs a spinlock // before modifying any internal static variables. The safety requirements of calling the // callback are delegated to the safety requirements of this function. let rc = unsafe { arm_ffa_register_direct_req2_handler(endpoint_service, Some(handler)) };
LkError::from_lk(rc)?;
Ok(())
}
/// Send an FFA_MSG_SEND_DIRECT_REQ2 request with a given UUID to an FFA endpoint with a given ID. pubfn msg_send_direct_req2(
endpoint_uuid: Uuid,
endpoint_id: EndpointID,
msg: &[u64; ARM_FFA_MSG_EXTENDED_ARGS_COUNT],
) -> Result<DirectResp2, LkError> { letmut resp = smc_ret18::new_zeroed(); let msg_ptr = msg.as_ptr(); // SAFETY: Resp points to a mutable smc_ret18. This function blocks and resp is // on the stack so it remains valid for the duration of the function call. let rc = unsafe { arm_ffa_msg_send_direct_req2(endpoint_uuid, endpoint_id, msg_ptr, &raw mut resp) };
LkError::from_lk(rc)?; // FFA_MSG_SEND_DIRECT_RESP2 puts the endpoint ID for the source (of the response) in the top 16 // bits of r1. It should match the endpoint_id of the request. let sender_id = (resp.r1 >> 16) as u16; if endpoint_id != sender_id {
error!( "endpoint IDs mismatch between request ({endpoint_id:?}) and response ({sender_id:?})"
); return Err(LkError::ERR_NOT_VALID);
}
// SAFETY: It's valid to access the union in resp as req2_params to create a copy since it was // just populated by the call to arm_ffa_msg_send_direct_req2.
Ok(DirectResp2 { sender_id, params: unsafe { resp.__bindgen_anon_1.req2_params } })
}
/// Share memory with an FFA endpoint specified by receiver id and returns an FFA memory handle. /// /// # Safety /// /// The callee must ensure the buffer described by paddr and num_ffa_pages may be shared with other /// FFA endpoints. Any accesses to that memory after it is shared must be synchronized using some /// well-defined protocol. The caller must also ensure that flags matches the arch_mmu_flags passed /// to vmm_alloc_obj when the shared memory was allocated. pubunsafefn mem_share_kernel_buffer(
receiver_id: u16,
paddr: paddr_t,
num_ffa_pages: usize,
arch_mmu_flags: ArchMmuFlags,
) -> Result<MemoryHandle, LkError> { letmut handle = 0; // SAFETY: Safety delegated to the caller. See function documentation for details. let rc = unsafe {
arm_ffa_mem_share_kernel_buffer(
receiver_id,
paddr,
num_ffa_pages,
arch_mmu_flags.bits(),
&raw mut handle,
)
};
LkError::from_lk(rc)?;
Ok(MemoryHandle(handle))
}
/// Reclaim memory shared with another FFA endpoint using the FFA memory handle. /// /// The other FFA endpoints must have relinquished the memory for this to succeed. If this fails it /// returns the memory handle to allow retrying the reclaim. pubfn mem_reclaim(handle: MemoryHandle) -> Result<(), (MemoryHandle, LkError)> { // SAFETY: Safety delegated to the caller. See function documentation for details. let rc = unsafe { arm_ffa_mem_reclaim(handle.get()) };
LkError::from_lk(rc).map_err(|e| (handle, e))?;
Ok(())
}
/// Returns the number of FFA endpoints exposing the given UUID. pubfn partition_info_get_count(uuid: Uuid) -> Result<usize, LkError> { letmut num_desc = 0; // SAFETY: `num_desc` is a valid storage location for the duration of the call. let rc = unsafe { arm_ffa_partition_info_get_count(uuid, &raw mut num_desc) }; if rc < 0 {
LkError::from_lk(rc)?;
}
Ok(num_desc)
}
/// Returns an iterator over info descriptors for all partitions exposing the given UUID. /// /// `descs` must be a slice of at least the number of partitions supporting the UUID (which can be /// discovered with `partition_info_get_count`). Otherwise an error is returned. Passing a larger /// slice than necessary will return an iterator over fewer elements. pubfn partition_info_get_desc(
uuid: Uuid,
descs: &mut [MaybeUninit<FFAPartInfoDesc>],
) -> Result<impl Iterator<Item = &FFAPartInfoDesc>, LkError> { letmut count_out = 0; let num_desc = descs.len(); // SAFETY: `desc` points to a slice large enough for the expected number of partitions that may // be returned and `count_out` is a valid storage location for the duration of the call. The // cast is necessary because the declaration generated by bindgen for // arm_ffa_partition_info_get_desc expects a *mut FFAPartInfoDesc even though the implementation // does not require the array elements to be initialized. let rc = unsafe {
arm_ffa_partition_info_get_desc(
uuid,
num_desc,
descs.as_mut_ptr().cast::<FFAPartInfoDesc>(),
&raw mut count_out,
)
}; if rc < 0 {
LkError::from_lk(rc)?;
} // SAFETY: If arm_ffa_partition_info_get_desc succeeded we can assume elements 0 though // `count_out` have valid partition info descriptors.
Ok(descs[0..count_out].iter().map(|e| unsafe { e.assume_init_ref() }))
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.