diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs index 36dc982686..95d8c5278f 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/drm_shim.rs @@ -45,6 +45,7 @@ struct DrmFile { unsafe fn write_handle_count(obj: *mut u8, count: u32) { let cobj = obj as *mut CallerGemObject; +// SAFETY: caller must verify the safety contract for this operation unsafe { (*cobj).handle_count = count; } @@ -52,12 +53,14 @@ unsafe fn write_handle_count(obj: *mut u8, count: u32) { unsafe fn write_size(obj: *mut u8, size: usize) { let cobj = obj as *mut CallerGemObject; +// SAFETY: caller must verify the safety contract for this operation unsafe { (*cobj).size = size; } } -unsafe fn read_size(obj: *mut u8) -> usize { +unsafe fn read_size(ob// SAFETY: caller must verify the safety contract for this operation +j: *mut u8) -> usize { let cobj = obj as *const CallerGemObject; unsafe { (*cobj).size } } @@ -455,7 +458,8 @@ pub extern "C" fn drm_dev_register(_dev: *mut u8, flags: u64) -> i32 { } #[no_mangle] -pub extern "C" fn drm_dev_unregister(_dev: *mut u8) {} +pub extern "C" fn drm_dev_unregister(_dev: *mut // SAFETY: caller must verify the safety contract for this operation +u8) {} #[no_mangle] pub extern "C" fn drm_gem_object_init(_dev: *mut u8, obj: *mut u8, size: usize) -> i32 { @@ -504,7 +508,8 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m return -EINVAL; } - let key = obj as usize; + let key = obj as u// SAFETY: caller must verify the safety contract for this operation +size; let size = unsafe { read_size(obj) }; let create = DrmGemCreateWire { @@ -537,7 +542,8 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m state.handles.push(response.handle); Some(state.handle_count) }); - let new_count = match new_count { + let // SAFETY: caller must verify the safety contract for this operation +new_count = match new_count { Some(c) => c, None => { log::error!( @@ -567,12 +573,14 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m } #[no_mangle] -pub extern "C" fn drm_gem_handle_delete(file: *mut u8, handle: u32) { +pub extern "C" fn drm_gem_handle_delete(file: *// SAFETY: caller must verify the safety contract for this operation +mut u8, handle: u32) { let obj_key = with_handles(|handles| handles.remove(&handle)); if let Some(key) = obj_key { with_objects(|objects| { - if let Some(state) = objects.get_mut(&key) { + if let Some(state) = objects.// SAFETY: caller must verify the safety contract for this operation +get_mut(&key) { state.handles.retain(|h| *h != handle); state.handle_count = state.handle_count.saturating_sub(1); unsafe { @@ -613,7 +621,8 @@ pub extern "C" fn drm_gem_handle_lookup(_file: *mut u8, handle: u32) -> *mut u8 } } None => { - log::warn!("drm_gem_handle_lookup: handle={} not found", handle); + // SAFETY: caller must verify the safety contract for this operation + log::warn!("drm_gem_handle_lookup: handle={} not found", handle); ptr::null_mut() } } @@ -641,7 +650,8 @@ pub extern "C" fn drm_gem_object_lookup(_file: *mut u8, handle: u32) -> *mut u8 } else { log::warn!( "drm_gem_object_lookup: handle={} maps to obj={:#x} but object released", - handle, + // SAFETY: caller must verify the safety contract for this operation + handle, key ); ptr::null_mut() @@ -662,7 +672,8 @@ pub extern "C" fn drm_gem_object_put(obj: *mut u8) { let key = obj as usize; with_objects(|objects| { if let Some(state) = objects.get_mut(&key) { - state.handle_count = state.handle_count.saturating_sub(1); + state.handle_count = state.handle_count.saturating_// SAFETY: caller must verify the safety contract for this operation +sub(1); unsafe { write_handle_count(obj, state.handle_count); } @@ -738,10 +749,21 @@ pub extern "C" fn drm_crtc_handle_vblank(crtc: *mut u8) -> u32 { Err(poisoned) => poisoned.into_inner(), }; let entry = counters.entry(key).or_insert(0); - *entry = entry.wrapping_add(1); + *entry = entry.wrappi// SAFETY: caller must verify the safety contract for this operation +ng_add(1); *entry } +#[no_mangle] +pub extern "C" fn drm_crtc_handle_vblank_get(crtc: *mut u8) -> u32 { + let key = crtc as usize; + let counters = match CRTC_VBLANK_COUNTERS.lock() { + Ok(c) => c, + Err(poisoned) => poisoned.into_inner(), + }; + counters.get(&key).copied().unwrap_or(0) +} + #[cfg(test)] mod tests { use super::*; @@ -871,4 +893,30 @@ mod tests { assert_eq!(b_first, 1, "fresh crtc B must start at counter 1"); assert_eq!(a_third, 3, "crtc A had two prior + this call = 3"); } + + #[test] + fn drm_crtc_handle_vblank_get_returns_counter_without_incrementing() { + let crtc: *mut u8 = 0x2400 as *mut u8; + let after_inc = drm_crtc_handle_vblank(crtc); + let v1 = drm_crtc_handle_vblank_get(crtc); + let v2 = drm_crtc_handle_vblank_get(crtc); + assert_eq!( + v1, after_inc, + "get() must return current counter value, not advance it" + ); + assert_eq!( + v2, after_inc, + "second get() must return the same value (no increment)" + ); + } + + #[test] + fn drm_crtc_handle_vblank_get_returns_zero_for_unseen_crtc() { + let crtc: *mut u8 = 0x2500 as *mut u8; + assert_eq!( + drm_crtc_handle_vblank_get(crtc), + 0, + "an unseen crtc pointer must return 0 from get()" + ); + } } diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs index fcf15a7c04..3aa6c0c158 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/error.rs @@ -267,7 +267,7 @@ mod tests { std::env::remove_var("REDBEAR_DRIVER_ERROR_FD"); } - fn test_handler(_severity: u8, _bdf: *const u8, _bdf_len: usize) -> u8 { + unsafe extern "C" fn test_handler(_severity: u8, _bdf: *const u8, _bdf_len: usize) -> u8 { 0 } }