veridian_kernel/drivers/
ramfb.rs1use crate::error::KernelError;
14
15#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
17const DRM_FORMAT_XRGB8888: u32 = 0x34325258; #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
22const FWCFG_BASE: usize = 0x0902_0000;
23
24#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
26const FWCFG_DATA: usize = 0x00;
27#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
28const FWCFG_SELECTOR: usize = 0x08;
29#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
30const FWCFG_DMA: usize = 0x10;
31
32#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
34const FWCFG_DMA_SELECT: u32 = 1 << 3;
35#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
36const FWCFG_DMA_WRITE: u32 = 1 << 4;
37
38#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
41#[repr(C, packed)]
42struct RamfbConfig {
43 addr: u64,
44 fourcc: u32,
45 flags: u32,
46 width: u32,
47 height: u32,
48 stride: u32,
49}
50
51#[repr(C, packed)]
53#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
54struct FwCfgDmaAccess {
55 control: u32,
56 length: u32,
57 address: u64,
58}
59
60#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
71pub fn init(width: u32, height: u32) -> Result<*mut u8, KernelError> {
72 use crate::mm::{FRAME_ALLOCATOR, FRAME_SIZE};
73
74 let stride = width * 4; let fb_size = (stride * height) as usize;
76
77 let num_frames = fb_size.div_ceil(FRAME_SIZE);
79 let frame_num = FRAME_ALLOCATOR
80 .lock()
81 .allocate_frames(num_frames, None)
82 .map_err(|_| KernelError::ResourceExhausted {
83 resource: "physical frames for ramfb",
84 })?;
85 let fb_phys = frame_num.as_addr().as_u64() as usize;
86
87 let fb_ptr = fb_phys as *mut u8;
90
91 unsafe {
94 core::ptr::write_bytes(fb_ptr, 0, fb_size);
95 }
96
97 let config = RamfbConfig {
99 addr: (fb_phys as u64).to_be(),
100 fourcc: DRM_FORMAT_XRGB8888.to_be(),
101 flags: 0u32.to_be(),
102 width: width.to_be(),
103 height: height.to_be(),
104 stride: stride.to_be(),
105 };
106
107 let selector = find_fwcfg_file("etc/ramfb").ok_or(KernelError::NotFound {
109 resource: "fw_cfg etc/ramfb selector",
110 id: 0,
111 })?;
112
113 write_fwcfg_dma(selector, &config as *const RamfbConfig as *const u8, 28)?;
115
116 Ok(fb_ptr)
117}
118
119#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
121pub fn init(_width: u32, _height: u32) -> Result<*mut u8, KernelError> {
122 Err(KernelError::OperationNotSupported {
123 operation: "ramfb (x86_64 uses UEFI framebuffer)",
124 })
125}
126
127#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
129fn find_fwcfg_file(name: &str) -> Option<u16> {
130 unsafe {
133 let selector_reg = (FWCFG_BASE + FWCFG_SELECTOR) as *mut u16;
134 selector_reg.write_volatile(0x0019u16.to_be());
135 }
136
137 let count: u32;
139 unsafe {
141 let data_reg = (FWCFG_BASE + FWCFG_DATA) as *const u32;
142 count = u32::from_be(data_reg.read_volatile());
143 }
144
145 for _ in 0..count {
148 let mut entry = [0u8; 64];
149 unsafe {
151 let data_reg = FWCFG_BASE as *const u8;
152 for byte in &mut entry {
153 *byte = data_reg.read_volatile();
154 }
155 }
156 let selector = u16::from_be_bytes([entry[4], entry[5]]);
157 let name_bytes = &entry[8..64];
159 let name_len = name_bytes.iter().position(|&b| b == 0).unwrap_or(56);
160 let entry_name = core::str::from_utf8(&name_bytes[..name_len]).unwrap_or("");
161 if entry_name == name {
162 return Some(selector);
163 }
164 }
165
166 None
167}
168
169#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
171fn write_fwcfg_dma(selector: u16, data: *const u8, length: u32) -> Result<(), KernelError> {
172 let dma_access = FwCfgDmaAccess {
173 control: (FWCFG_DMA_SELECT | FWCFG_DMA_WRITE | ((selector as u32) << 16)).to_be(),
174 length: length.to_be(),
175 address: (data as u64).to_be(),
176 };
177
178 let dma_addr = &dma_access as *const FwCfgDmaAccess as u64;
179
180 unsafe {
183 let dma_reg_hi = (FWCFG_BASE + FWCFG_DMA) as *mut u32;
184 let dma_reg_lo = (FWCFG_BASE + FWCFG_DMA + 4) as *mut u32;
185 dma_reg_hi.write_volatile(((dma_addr >> 32) as u32).to_be());
186 dma_reg_lo.write_volatile((dma_addr as u32).to_be());
187 }
188
189 let control_ptr = core::ptr::addr_of!(dma_access.control);
192 for _ in 0..1_000_000 {
196 let val = unsafe { core::ptr::read_unaligned(control_ptr) };
197 if val == 0 {
198 return Ok(());
199 }
200 core::hint::spin_loop();
201 }
202
203 Err(KernelError::Timeout {
204 operation: "fw_cfg DMA write",
205 duration_ms: 0,
206 })
207}