From e59d4ac7e1398ec4ada984bda7561714c2ed384f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 5 Jul 2025 15:21:40 +0200 Subject: [PATCH 1/5] graphics/vesad: Move FrameBuffer to scheme.rs --- graphics/vesad/src/framebuffer.rs | 59 ------------------------------ graphics/vesad/src/main.rs | 4 +-- graphics/vesad/src/scheme.rs | 60 +++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 64 deletions(-) delete mode 100644 graphics/vesad/src/framebuffer.rs diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs deleted file mode 100644 index 7eeab2fe4d..0000000000 --- a/graphics/vesad/src/framebuffer.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::ptr; - -pub struct FrameBuffer { - pub onscreen: *mut [u32], - pub phys: usize, - pub width: usize, - pub height: usize, - pub stride: usize, -} - -impl FrameBuffer { - pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { - let size = stride * height; - let virt = common::physmap( - phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - ) - .expect("vesad: failed to map framebuffer") as *mut u32; - - let onscreen = ptr::slice_from_raw_parts_mut(virt, size); - - Self { - onscreen, - phys, - width, - height, - stride, - } - } - - pub unsafe fn parse(var: &str) -> Option { - fn parse_number(part: &str) -> Option { - let (start, radix) = if part.starts_with("0x") { - (2, 16) - } else { - (0, 10) - }; - match usize::from_str_radix(&part[start..], radix) { - Ok(ok) => Some(ok), - Err(err) => { - eprintln!("vesad: failed to parse '{}': {}", part, err); - None - } - } - } - - let mut parts = var.split(','); - let phys = parse_number(parts.next()?)?; - let width = parse_number(parts.next()?)?; - let height = parse_number(parts.next()?)?; - let stride = parse_number(parts.next()?)?; - Some(Self::new(phys, width, height, stride)) - } -} diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index e107129af0..7549e86a93 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -9,10 +9,8 @@ use std::fs::File; use std::io::Write; use std::os::fd::AsRawFd; -use crate::framebuffer::FrameBuffer; -use crate::scheme::FbAdapter; +use crate::scheme::{FbAdapter, FrameBuffer}; -mod framebuffer; mod scheme; fn main() { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 63a83896c8..42e4054e41 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -6,8 +6,6 @@ use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapt use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; -use crate::framebuffer::FrameBuffer; - pub struct FbAdapter { pub framebuffers: Vec, } @@ -60,6 +58,64 @@ impl GraphicsAdapter for FbAdapter { } } +pub struct FrameBuffer { + pub onscreen: *mut [u32], + pub phys: usize, + pub width: usize, + pub height: usize, + pub stride: usize, +} + +impl FrameBuffer { + pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + let size = stride * height; + let virt = common::physmap( + phys, + size * 4, + common::Prot { + read: true, + write: true, + }, + common::MemoryType::WriteCombining, + ) + .expect("vesad: failed to map framebuffer") as *mut u32; + + let onscreen = ptr::slice_from_raw_parts_mut(virt, size); + + Self { + onscreen, + phys, + width, + height, + stride, + } + } + + pub unsafe fn parse(var: &str) -> Option { + fn parse_number(part: &str) -> Option { + let (start, radix) = if part.starts_with("0x") { + (2, 16) + } else { + (0, 10) + }; + match usize::from_str_radix(&part[start..], radix) { + Ok(ok) => Some(ok), + Err(err) => { + eprintln!("vesad: failed to parse '{}': {}", part, err); + None + } + } + } + + let mut parts = var.split(','); + let phys = parse_number(parts.next()?)?; + let width = parse_number(parts.next()?)?; + let height = parse_number(parts.next()?)?; + let stride = parse_number(parts.next()?)?; + Some(Self::new(phys, width, height, stride)) + } +} + pub struct GraphicScreen { width: usize, height: usize, From 9abeafde8d4296e559a02b2a66a8b4b55dc2e8e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 5 Jul 2025 15:43:21 +0200 Subject: [PATCH 2/5] graphics: Move disable-graphical-debug to driver-graphics This ensures it graphical debug gets disabled even when vesad never runs. --- graphics/driver-graphics/src/lib.rs | 18 +++++++++++++++++- graphics/vesad/src/main.rs | 19 +------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index e9971323fb..cb3ddf741d 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,8 @@ #![feature(slice_as_array)] use std::collections::{BTreeMap, HashMap}; -use std::io; +use std::fs::File; +use std::io::{self, Write}; use std::mem::transmute; use std::sync::Arc; @@ -53,6 +54,7 @@ pub struct GraphicsScheme { adapter: T, scheme_name: String, + disable_graphical_debug: Option, socket: Socket, next_id: usize, handles: BTreeMap>, @@ -83,9 +85,15 @@ impl GraphicsScheme { assert!(scheme_name.starts_with("display")); let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme"); + let disable_graphical_debug = Some( + File::open("/scheme/debug/disable-graphical-debug") + .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), + ); + GraphicsScheme { adapter, scheme_name, + disable_graphical_debug, socket, next_id: 0, handles: BTreeMap::new(), @@ -111,6 +119,14 @@ impl GraphicsScheme { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); + // Disable the kernel graphical debug writing once switching vt's for the + // first time. This way the kernel graphical debug remains enabled if the + // userspace logging infrastructure doesn't start up because for example a + // kernel panic happened prior to it starting up or logd crashed. + if let Some(mut disable_graphical_debug) = self.disable_graphical_debug.take() { + let _ = disable_graphical_debug.write(&[1]); + } + self.active_vt = vt_event.vt; let vt_state = diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 7549e86a93..be52174509 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -3,10 +3,8 @@ extern crate syscall; use driver_graphics::GraphicsScheme; use event::{user_data, EventQueue}; -use inputd::{DisplayHandle, VtEventKind}; +use inputd::DisplayHandle; use std::env; -use std::fs::File; -use std::io::Write; use std::os::fd::AsRawFd; use crate::scheme::{FbAdapter, FrameBuffer}; @@ -103,11 +101,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { ) .unwrap(); - let mut disable_graphical_debug = Some( - File::open("/scheme/debug/disable-graphical-debug") - .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), - ); - libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); @@ -123,16 +116,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { .read_vt_event() .expect("vesad: failed to read display handle") { - if let VtEventKind::Activate = vt_event.kind { - // Disable the kernel graphical debug writing once switching vt's for the - // first time. This way the kernel graphical debug remains enabled if the - // userspace logging infrastructure doesn't start up because for example a - // kernel panic happened prior to it starting up or logd crashed. - if let Some(mut disable_graphical_debug) = disable_graphical_debug.take() { - let _ = disable_graphical_debug.write(&[1]); - } - } - scheme.handle_vt_event(vt_event); } } From 918efd01cdc18b274a139b5a75742040d5f05141 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:30:39 +0100 Subject: [PATCH 3/5] graphics/fbcond: Inline open_display --- graphics/fbcond/src/display.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d95d0c7789..218f8f2284 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -26,7 +26,8 @@ impl Display { /// Re-open the display after a handoff. pub fn reopen_for_handoff(&mut self) { - let new_display_handle = Self::open_display(&self.input_handle).unwrap(); + let display_file = self.input_handle.open_display().unwrap(); + let new_display_handle = V1GraphicsHandle::from_file(display_file).unwrap(); eprintln!("fbcond: Opened new display"); @@ -49,12 +50,6 @@ impl Display { } } - fn open_display(input_handle: &ConsumerHandle) -> io::Result { - let display_file = input_handle.open_display()?; - - V1GraphicsHandle::from_file(display_file) - } - pub fn sync_rect(&mut self, sync_rect: Damage) { if let Some(map) = &self.map { map.display_handle.sync_rect(sync_rect).unwrap(); From ded7a6ed863180a1a11becfed21161b9ab22bf99 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 15:30:05 +0200 Subject: [PATCH 4/5] graphics/graphics-ipc: Update handle doc comments --- graphics/graphics-ipc/src/v1.rs | 2 ++ graphics/graphics-ipc/src/v2.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index a29258db9c..640d117bab 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -11,6 +11,8 @@ pub use crate::common::DisplayMap; /// /// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be /// handled separately and doesn't support page flipping. +/// +/// This API is stable. No breaking changes are allowed to be made without a version bump. pub struct V1GraphicsHandle { file: File, } diff --git a/graphics/graphics-ipc/src/v2.rs b/graphics/graphics-ipc/src/v2.rs index fa316d96b0..689e865bc2 100644 --- a/graphics/graphics-ipc/src/v2.rs +++ b/graphics/graphics-ipc/src/v2.rs @@ -33,10 +33,13 @@ unsafe fn sys_call( )) } -/// A graphics handle using the (currently unstable) v2 graphics API. +/// A graphics handle using the v2 graphics API. /// /// The v2 graphics API allows creating framebuffers on the fly, using them for page flipping and /// handles all displays using a single fd. +/// +/// This API is not yet stable. Do not depend on it outside of the drivers repo until it has been +/// stabilized. pub struct V2GraphicsHandle { file: File, } From 93e95f6fe8a5e8be25ae33bdefb015485ea91a2f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:22:41 +0200 Subject: [PATCH 5/5] graphics: Fix memory leak when resizing the display --- graphics/driver-graphics/src/lib.rs | 17 +++++++++++++++++ graphics/fbbootlogd/src/scheme.rs | 2 ++ graphics/graphics-ipc/src/v2.rs | 21 ++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index cb3ddf741d..383e34cb7f 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -496,6 +496,23 @@ impl SchemeSync for GraphicsScheme { Ok(size_of::()) } + ipc::DESTROY_DUMB_FRAMEBUFFER => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::< + &mut [u8; size_of::()], + &mut ipc::DestroyDumbFramebuffer, + >(payload.as_mut_array().unwrap()) + }; + + if fbs.remove(&{ payload.fb_id }).is_none() { + return Err(Error::new(ENOENT)); + } + + Ok(size_of::()) + } ipc::UPDATE_PLANE => { if payload.len() < size_of::() { return Err(Error::new(EINVAL)); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 1cf2f21cf2..f6180e280b 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -95,6 +95,8 @@ impl FbbootlogScheme { }, ); + let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); + map.fb = fb; map.inner = new_map; diff --git a/graphics/graphics-ipc/src/v2.rs b/graphics/graphics-ipc/src/v2.rs index 689e865bc2..ca23f82e25 100644 --- a/graphics/graphics-ipc/src/v2.rs +++ b/graphics/graphics-ipc/src/v2.rs @@ -124,6 +124,19 @@ impl V2GraphicsHandle { Ok(unsafe { DisplayMap::new(offscreen, width as usize, height as usize) }) } + pub fn destroy_dumb_framebuffer(&self, id: usize) -> io::Result { + let mut cmd = ipc::DestroyDumbFramebuffer { fb_id: id }; + unsafe { + sys_call( + &self.file, + &mut cmd, + 0, + &[ipc::DESTROY_DUMB_FRAMEBUFFER, 0, 0], + )?; + } + Ok(cmd.fb_id) + } + pub fn update_plane(&self, display_id: usize, fb_id: usize, damage: Damage) -> io::Result<()> { let mut cmd = ipc::UpdatePlane { display_id, @@ -172,7 +185,13 @@ pub mod ipc { pub offset: usize, } - pub const UPDATE_PLANE: u64 = 5; + pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5; + #[repr(C, packed)] + pub struct DestroyDumbFramebuffer { + pub fb_id: usize, + } + + pub const UPDATE_PLANE: u64 = 6; #[repr(C, packed)] pub struct UpdatePlane { pub display_id: usize,