From a07c2911ca51522b941339a0ee0393f7a2bf9752 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Wed, 3 Sep 2025 15:43:05 +0930 Subject: [PATCH 1/6] Fix scaling mode set to FitToLayer even when other scaling modes are selected. --- src/gpu/surface.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gpu/surface.rs b/src/gpu/surface.rs index 3552af11..8f15c0bb 100755 --- a/src/gpu/surface.rs +++ b/src/gpu/surface.rs @@ -197,9 +197,6 @@ impl Surface { .set_scaling_mode(vi::ScalingMode::PreserveAspectRatio, layer_id)?; } } - gpu_guard - .application_display_service - .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)?; system_display_service.set_layer_position(x, y, layer_id)?; From 1d2e66d2567a4f1980b4eb2d005ac783089ab110 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Thu, 4 Sep 2025 14:16:50 +0930 Subject: [PATCH 2/6] Add missing semicolon. --- src/gpu/surface.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpu/surface.rs b/src/gpu/surface.rs index 8f15c0bb..23b29e67 100755 --- a/src/gpu/surface.rs +++ b/src/gpu/surface.rs @@ -177,7 +177,7 @@ impl Surface { )?; gpu_guard .application_display_service - .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)? + .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)?; } ScaleMode::FitToLayer { width, height } => { system_display_service.set_layer_size(layer_id, width as u64, height as u64)?; From b7af49ff1301806c5676a124447cfde146e9c349 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Sun, 14 Sep 2025 22:55:31 +0930 Subject: [PATCH 3/6] Fix scaling mode IPC call with wrong IPC request ID. --- src/ipc/sf/vi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ipc/sf/vi.rs b/src/ipc/sf/vi.rs index b3f4d233..5ea293ba 100755 --- a/src/ipc/sf/vi.rs +++ b/src/ipc/sf/vi.rs @@ -109,7 +109,7 @@ pub trait ApplicationDisplay { out_native_window: sf::OutMapAliasBuffer<'_, u8>, ) -> usize; #[ipc_rid(2021)] - fn set_scaling_mode(&mut self, scaling_mode: ScalingMode, layer_id: LayerId); + fn destroy_managed_layer(&mut self, id: LayerId); #[ipc_rid(2030)] fn create_stray_layer( &mut self, @@ -119,6 +119,8 @@ pub trait ApplicationDisplay { ) -> (LayerId, usize); #[ipc_rid(2031)] fn destroy_stray_layer(&mut self, id: LayerId); + #[ipc_rid(2101)] + fn set_scaling_mode(&mut self, scaling_mode: ScalingMode, layer_id: LayerId); #[ipc_rid(5202)] fn get_display_vsync_event(&self, id: DisplayId) -> sf::CopyHandle; } From 06a3a94f60aa5374a62632eb72dd3ed8bed775a1 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Sun, 14 Sep 2025 23:21:47 +0930 Subject: [PATCH 4/6] Adjust error handling during surface creation to prevent dangling layers. --- src/gpu/surface.rs | 90 ++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/src/gpu/surface.rs b/src/gpu/surface.rs index 23b29e67..e5ff32b8 100755 --- a/src/gpu/surface.rs +++ b/src/gpu/surface.rs @@ -89,7 +89,10 @@ impl Surface { )?; let mut parcel = parcel::Parcel::new(); parcel.load_from(native_window); - let binder_handle = parcel.read::()?.handle; + let binder_handle = parcel + .read::() + .expect("ParcelData should always be readable if create_stray_layer succeeds.") + .handle; (binder_handle, layer_id) }; @@ -164,48 +167,57 @@ impl Surface { sf::Buffer::from_other_mut_var(&mut native_window), )?; - let mut binder_parcel = parcel::Parcel::new(); - binder_parcel.load_from(native_window); - let binder_handle = binder_parcel.read::()?.handle; - - match scaling { - ScaleMode::None => { - system_display_service.set_layer_size( - layer_id, - framebuffer_width as u64, - framebuffer_height as u64, - )?; - gpu_guard - .application_display_service - .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)?; + let binder_handle = match try { + let mut binder_parcel = parcel::Parcel::new(); + binder_parcel.load_from(native_window); + let binder_handle = binder_parcel.read::()?.handle; + match scaling { + ScaleMode::None => { + gpu_guard + .application_display_service + .set_scaling_mode(vi::ScalingMode::None, layer_id)?; + system_display_service.set_layer_size( + layer_id, + framebuffer_width as u64, + framebuffer_height as u64, + )?; + } + ScaleMode::FitToLayer { width, height } => { + gpu_guard + .application_display_service + .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)?; + system_display_service.set_layer_size(layer_id, width as u64, height as u64)?; + } + ScaleMode::PreseveAspect { height } => { + gpu_guard + .application_display_service + .set_scaling_mode(vi::ScalingMode::PreserveAspectRatio, layer_id)?; + system_display_service.set_layer_size( + layer_id, + (framebuffer_width as f32 * (height as f32) / (framebuffer_height as f32)) + as u64, + height as u64, + )?; + } } - ScaleMode::FitToLayer { width, height } => { - system_display_service.set_layer_size(layer_id, width as u64, height as u64)?; - gpu_guard - .application_display_service - .set_scaling_mode(vi::ScalingMode::FitToLayer, layer_id)?; - } - ScaleMode::PreseveAspect { height } => { - system_display_service.set_layer_size( - layer_id, - (framebuffer_width as f32 * (height as f32) / (framebuffer_height as f32)) - as u64, - height as u64, - )?; - gpu_guard - .application_display_service - .set_scaling_mode(vi::ScalingMode::PreserveAspectRatio, layer_id)?; - } - } - system_display_service.set_layer_position(x, y, layer_id)?; + system_display_service.set_layer_position(x, y, layer_id)?; - let z_value = match z { - LayerZ::Max => system_display_service.get_z_order_count_max(display_id)?, - LayerZ::Min => system_display_service.get_z_order_count_min(display_id)?, - LayerZ::Value(z_val) => z_val, + let z_value = match z { + LayerZ::Max => system_display_service.get_z_order_count_max(display_id)?, + LayerZ::Min => system_display_service.get_z_order_count_min(display_id)?, + LayerZ::Value(z_val) => z_val, + }; + system_display_service.set_layer_z(layer_id, z_value)?; + + binder_handle + } { + Err(e) => { + manager_display_service.destroy_managed_layer(layer_id)?; + return Err(e); + } + Ok(handle) => handle, }; - system_display_service.set_layer_z(layer_id, z_value)?; drop(gpu_guard); Self::new_from_parts( From 4eaba741d7c4eade3ca5c17d5294b73ce189ca6e Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Sun, 14 Sep 2025 23:22:21 +0930 Subject: [PATCH 5/6] Refactor NvDrv type to prevent allocation --- src/gpu.rs | 108 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 26 deletions(-) diff --git a/src/gpu.rs b/src/gpu.rs index 54db5a7b..19cd5a8d 100755 --- a/src/gpu.rs +++ b/src/gpu.rs @@ -1,6 +1,5 @@ //! Graphics and GPU support and utils -use ::alloc::boxed::Box; use ::alloc::sync::Arc; use crate::ipc::sf; @@ -10,10 +9,10 @@ use crate::service; use crate::service::applet; use crate::service::dispdrv; use crate::service::nv; -use crate::service::nv::INvDrvClient; +use crate::service::nv::{ErrorCode, Fd,INvDrvClient, IoctlId}; use crate::service::vi; use crate::service::vi::{ - ApplicationDisplayRootService, IApplicationDisplayClient, ManagerDisplayRootService, + ApplicationDisplayRootService, ApplicationDisplay, IApplicationDisplayClient, ManagerDisplayRootService, SystemDisplayRootService, }; use crate::svc; @@ -928,19 +927,76 @@ pub fn convert_nv_error_code(err: nv::ErrorCode) -> Result<()> { } /// A holder for our `*RootService` objects, just to keep them alive for the lifetime of the `Context` -#[allow(missing_docs)] pub enum RootServiceHolder { + /// Application Service Application(ApplicationDisplayRootService), + /// Manager Service Manager(ManagerDisplayRootService), + /// System Service System(SystemDisplayRootService), } +/// A holder for our `nvdrv` service objects +pub enum NvDrvServiceHolder { + /// Application Service + Application(nv::ApplicationNvDrvService), + /// Applet Service + Applet(nv::AppletNvDrvService), + /// System Service + System(nv::SystemNvDrvService) +} + +impl NvDrvServiceHolder { + fn open(&self, path: sf::InMapAliasBuffer<'_, u8>) -> Result<(Fd, ErrorCode)> { + match self { + Self::Application(s) => s.open(path), + Self::Applet(s) => s.open(path), + Self::System(s) => s.open(path) + } + } + fn ioctl(&self, fd: Fd, id: IoctlId, in_buf: sf::InOutAutoSelectBuffer<'_, u8>) -> Result { + match self { + Self::Application(s) => s.ioctl(fd, id, in_buf), + Self::Applet(s) => s.ioctl(fd, id, in_buf), + Self::System(s) => s.ioctl(fd, id, in_buf) + } + } + fn close(&self, fd: Fd) -> Result { + match self { + Self::Application(s) => s.close(fd), + Self::Applet(s) => s.close(fd), + Self::System(s) => s.close(fd) + } + } + fn initialize( + &self, + transfer_mem_size: u32, + self_process_handle: sf::CopyHandle, + transfer_mem_handle: sf::CopyHandle, + ) -> Result { + match self { + Self::Application(s) => s.initialize(transfer_mem_size, self_process_handle, transfer_mem_handle), + Self::Applet(s) => s.initialize(transfer_mem_size, self_process_handle, transfer_mem_handle), + Self::System(s) => s.initialize(transfer_mem_size, self_process_handle, transfer_mem_handle) + } + } + + fn close_self(&mut self) { + use crate::ipc::client::IClientObject; + match self { + Self::Application(s) => s.get_session_mut().close(), + Self::Applet(s) => s.get_session_mut().close(), + Self::System(s) => s.get_session_mut().close() + } + } +} + /// Represents a graphics context #[allow(dead_code)] pub struct Context { vi_service: RootServiceHolder, - nvdrv_service: Box, - application_display_service: Box, + nvdrv_service: NvDrvServiceHolder, + application_display_service: ApplicationDisplay, hos_binder_driver: Arc, transfer_mem: alloc::Buffer, transfer_mem_handle: svc::Handle, @@ -969,7 +1025,7 @@ impl Context { use vi::IManagerDisplayRootClient; let vi_srv = service::new_service_object::()?; let app_disp_srv = - Box::new(vi_srv.get_display_service(vi::DisplayServiceMode::Privileged)?); + vi_srv.get_display_service(vi::DisplayServiceMode::Privileged)?; (RootServiceHolder::Manager(vi_srv), app_disp_srv) } @@ -977,7 +1033,7 @@ impl Context { use vi::ISystemDisplayRootClient; let vi_srv = service::new_service_object::()?; let app_disp_srv = - Box::new(vi_srv.get_display_service(vi::DisplayServiceMode::Privileged)?); + vi_srv.get_display_service(vi::DisplayServiceMode::Privileged)?; (RootServiceHolder::System(vi_srv), app_disp_srv) } @@ -985,21 +1041,21 @@ impl Context { use vi::IApplicationDisplayRootClient; let vi_srv = service::new_service_object::()?; let app_disp_srv = - Box::new(vi_srv.get_display_service(vi::DisplayServiceMode::User)?); + vi_srv.get_display_service(vi::DisplayServiceMode::User)?; (RootServiceHolder::Application(vi_srv), app_disp_srv) } }; - let nvdrv_srv: Box = match nv_kind { + let nvdrv_srv= match nv_kind { NvDrvServiceKind::Application => { - Box::new(service::new_service_object::()?) + NvDrvServiceHolder::Application(service::new_service_object::()?) } NvDrvServiceKind::Applet => { - Box::new(service::new_service_object::()?) + NvDrvServiceHolder::Applet(service::new_service_object::()?) } NvDrvServiceKind::System => { - Box::new(service::new_service_object::()?) + NvDrvServiceHolder::System(service::new_service_object::()?) } }; @@ -1023,10 +1079,10 @@ impl Context { /// * `nvdrv_srv`: The NV [`INvDrvClient`] service object /// * `transfer_mem_size`: The transfer memory size to use /// * `nv_host_as_gpu`: Flag whether to open a handle to the GPU for hardware accelerated rendering. - pub fn from( + fn from( vi_srv: RootServiceHolder, - application_display_srv: Box, - mut nvdrv_srv: Box, + application_display_srv: ApplicationDisplay, + mut nvdrv_srv: NvDrvServiceHolder, transfer_mem_size: usize, nv_host_as_gpu: bool, ) -> Result { @@ -1074,7 +1130,7 @@ impl Context { let _ = nvdrv_srv.close(nvhostctrl_fd); let _ = nvdrv_srv.close(transfer_mem_handle); - nvdrv_srv.get_session_mut().close(); + nvdrv_srv.close_self(); svc::close_handle(transfer_mem_handle).unwrap(); let _ = wait_for_permission(transfer_mem.ptr, MemoryPermission::Write(), None); return Err(rc); @@ -1094,26 +1150,26 @@ impl Context { }) } - /// Gets the underlying NV [`INvDrvClient`] service object - pub fn nvdrv_service(&self) -> &dyn INvDrvClient { - self.nvdrv_service.as_ref() + /// Gets the wrapped NV [`INvDrvClient`] service object + pub fn nvdrv_service(&self) -> &NvDrvServiceHolder { + &self.nvdrv_service } - /// Gets the underlying NV [`INvDrvClient`] service object mutably - pub fn nvdrv_service_mut(&mut self) -> &mut dyn INvDrvClient { - self.nvdrv_service.as_mut() + /// Gets the wrapped NV [`INvDrvClient`] service object mutably + pub fn nvdrv_service_mut(&mut self) -> &mut NvDrvServiceHolder { + &mut self.nvdrv_service } /// Gets the underlying [`IApplicationDisplayClient`] object pub fn get_application_display_service(&self) -> &dyn vi::IApplicationDisplayClient { - self.application_display_service.as_ref() + & self.application_display_service } /// Gets the underlying [`IApplicationDisplayClient`] object mutably pub fn get_application_display_service_mut( &mut self, ) -> &mut dyn vi::IApplicationDisplayClient { - self.application_display_service.as_mut() + &mut self.application_display_service } /// Gets the underlying [`IHOSBinderDriverClient`][`dispdrv::IHOSBinderDriverClient`] object @@ -1131,7 +1187,7 @@ impl Drop for Context { self.nvdrv_service.close(self.nvhostctrl_fd); self.nvdrv_service.close(self.transfer_mem_handle); - self.nvdrv_service.get_session_mut().close(); + self.nvdrv_service.close_self(); svc::close_handle(self.transfer_mem_handle).unwrap(); wait_for_permission(self.transfer_mem.ptr, MemoryPermission::Write(), None); } From 0422b562d4e93977f44061c45e18d10671267b60 Mon Sep 17 00:00:00 2001 From: Philip Woolford Date: Sun, 14 Sep 2025 23:23:01 +0930 Subject: [PATCH 6/6] Changes for pointer provenance APIs --- src/hbl.rs | 8 ++++---- src/ipc.rs | 19 +++++++++++-------- src/rrt0.rs | 10 ++++++---- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/hbl.rs b/src/hbl.rs index b22fe817..b3adb848 100755 --- a/src/hbl.rs +++ b/src/hbl.rs @@ -204,11 +204,11 @@ pub static G_NEXT_LOAD_PATH: Mutex>> = Mute pub static G_NEXT_LOAD_ARGV: Mutex>> = Mutex::new(None); pub(crate) fn set_next_load_entry_ptr( - next_load_path: &'static mut ArrayString<512>, - next_load_argv: &'static mut ArrayString<2048>, + next_load_path: Option<&'static mut ArrayString<512>>, + next_load_argv: Option<&'static mut ArrayString<2048>>, ) { - *G_NEXT_LOAD_PATH.lock() = Some(next_load_path); - *G_NEXT_LOAD_ARGV.lock() = Some(next_load_argv); + *G_NEXT_LOAD_PATH.lock() = next_load_path; + *G_NEXT_LOAD_ARGV.lock() = next_load_argv; } /// Gets the next load path, AKA the path of the homebrew NRO which will be executed after this one exits diff --git a/src/ipc.rs b/src/ipc.rs index a035d114..e39b916b 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -122,9 +122,10 @@ impl BufferDescriptor { } pub fn new(buffer: *const u8, buffer_size: usize, flags: BufferFlags) -> Self { - let address_low = buffer as usize as u32; - let address_mid = ((buffer as usize) >> 32) as u32; - let address_high = ((buffer as usize) >> 36) as u32; + let buffer = buffer.expose_provenance(); + let address_low = buffer as u32; + let address_mid = (buffer >> 32) as u32; + let address_high = (buffer >> 36) as u32; let size_low = buffer_size as u32; let size_high = (buffer_size >> 32) as u32; @@ -171,9 +172,10 @@ impl SendStaticDescriptor { } pub fn new(buffer: *const u8, buffer_size: usize, index: u32) -> Self { - let address_low = buffer as usize as u32; - let address_mid = ((buffer as usize) >> 32) as u32; - let address_high = ((buffer as usize) >> 36) as u32; + let buffer = buffer.expose_provenance(); + let address_low = buffer as u32; + let address_mid = (buffer >> 32) as u32; + let address_high = (buffer >> 36) as u32; let mut bits: u32 = 0; write_bits!(0, 5, bits, index); @@ -213,8 +215,9 @@ impl ReceiveStaticDescriptor { } pub fn new(buffer: *const u8, buffer_size: usize) -> Self { - let address_low = buffer as usize as u32; - let address_high = ((buffer as usize) >> 32) as u32; + let buffer = buffer.expose_provenance(); + let address_low = buffer as u32; + let address_high = (buffer >> 32) as u32; let mut bits: u32 = 0; write_bits!(0, 15, bits, address_high); diff --git a/src/rrt0.rs b/src/rrt0.rs index 2309ac7f..124a6529 100644 --- a/src/rrt0.rs +++ b/src/rrt0.rs @@ -224,10 +224,12 @@ unsafe fn normal_entry(loader_mode: LoaderMode, exit_config: Option) -> hbl::AbiConfigEntryKey::NextLoadPath => { // lengths from nx-hbloader:source/main.c // https://github.com/switchbrew/nx-hbloader/blob/cd6a723acbeabffd827a8bdc40563066f5401fb7/source/main.c#L13-L14 - let next_load_path: &'static mut util::ArrayString<512> = - core::mem::transmute((*abi_entry).value[0]); - let next_load_argv: &'static mut util::ArrayString<2048> = - core::mem::transmute((*abi_entry).value[1]); + let next_load_path= + core::ptr::with_exposed_provenance_mut::>((*abi_entry).value[0] as usize) + .as_mut(); + let next_load_argv= + core::ptr::with_exposed_provenance_mut::>((*abi_entry).value[1] as usize) + .as_mut(); hbl::set_next_load_entry_ptr(next_load_path, next_load_argv); } hbl::AbiConfigEntryKey::OverrideHeap => {