1use crate::util::maur::{self, TaskWritable};
6use crate::util::{KgslCmdBatchFlags, KgslContextFlags, KgslMemFlags};
7use fdio::service_connect;
8use kgsl_libmagma::{
9 Buffer, Connection, Context, Device, QueryOutput, Semaphore, initialize_logging,
10};
11use kgsl_magma_params::{AdrenoKgslParams, MAGMA_QCOM_ADRENO_QUERY_KGSL_PARAMS};
12use kgsl_strings::{ioctl_kgsl, kgsl_prop};
13use magma::{
14 MAGMA_MAP_FLAG_READ, MAGMA_MAP_FLAG_WRITE, MAGMA_QUERY_DEVICE_ID, MAGMA_QUERY_VENDOR_ID,
15};
16use range_alloc::RangeAllocator;
17use starnix_core::mm::memory::MemoryObject;
18use starnix_core::mm::{MappingName, MemoryAccessorExt, PAGE_SIZE};
19use starnix_core::task::CurrentTask;
20use starnix_core::vfs::{FileObject, FileOps, FsNode};
21use starnix_core::{fileops_impl_dataless, fileops_impl_nonseekable, fileops_impl_noop_sync};
22use starnix_logging::{log_error, log_info, log_warn, track_stub};
23use starnix_sync::{Locked, Mutex, Unlocked};
24use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
25use starnix_uapi::device_type::DeviceType;
26use starnix_uapi::errors::Errno;
27use starnix_uapi::open_flags::OpenFlags;
28use starnix_uapi::user_address::{UserAddress, UserRef};
29use starnix_uapi::{errno, error, kgsl_command_object, kgsl_command_syncpoint, uapi};
30use std::collections::HashMap;
31use std::collections::hash_map::Entry;
32use std::sync::atomic::{AtomicU32, Ordering};
33use std::sync::{Arc, Once};
34
35#[cfg(feature = "starnix-kgsl-debug")]
36#[macro_export]
37macro_rules! kgsl_debug {
38 ($fmt:expr $(, $arg:expr)*) => {
39 log_info!("kgsl: {}:{}: {}", file!(), line!(), format_args!($fmt $(, $arg)*));
40 };
41}
42
43#[cfg(not(feature = "starnix-kgsl-debug"))]
44#[macro_export]
45macro_rules! kgsl_debug {
46 ($($arg:tt)*) => {};
47}
48
49const BUFFER_ALIGNMENT: u64 = 65536;
53
54trait RangeAllocatorExt {
56 fn create(size: u64) -> Self;
57 fn allocate(&mut self, size: u64) -> Option<u64>;
58 fn free(&mut self, gpuaddr: u64, size: u64);
59}
60
61impl RangeAllocatorExt for RangeAllocator<u64> {
62 fn create(size: u64) -> Self {
63 RangeAllocator::new(0..(size / BUFFER_ALIGNMENT))
64 }
65
66 fn allocate(&mut self, size: u64) -> Option<u64> {
67 self.allocate_range(size.div_ceil(BUFFER_ALIGNMENT))
68 .ok()
69 .map(|r| r.start * BUFFER_ALIGNMENT)
70 }
71
72 fn free(&mut self, gpuaddr: u64, size: u64) {
73 let start_unit = gpuaddr / BUFFER_ALIGNMENT;
74 let units = size.div_ceil(BUFFER_ALIGNMENT);
75 self.free_range(start_unit..(start_unit + units));
76 }
77}
78
79pub struct KgslFile {
80 #[expect(dead_code)]
83 device: Device,
84 connection: Connection,
85 adreno_kgsl_params: AdrenoKgslParams,
86 syncsources: Mutex<HashMap<u32, Semaphore>>,
88 next_syncsource_id: AtomicU32,
89 gpuobjs: Mutex<HashMap<u32, GpuObject>>,
91 next_gpuobj_id: AtomicU32,
92 allocator: Mutex<RangeAllocator<u64>>,
93 shadow_properties: uapi::kgsl_shadowprop,
94 contexts: Mutex<HashMap<u32, Context>>,
96 next_context_id: AtomicU32,
97}
98
99struct GpuObject {
100 buffer: Buffer,
101 flags: u64,
102 size: u64,
103 mmapsize: u64,
104 gpuaddr: u64,
105}
106
107fn map_flags(flags: KgslMemFlags) -> Result<u64, Errno> {
108 match (flags.gpu_read_only(), flags.gpu_write_only()) {
109 (true, false) => Ok(MAGMA_MAP_FLAG_READ),
110 (false, true) => Ok(MAGMA_MAP_FLAG_WRITE),
111 (false, false) => Ok(MAGMA_MAP_FLAG_READ | MAGMA_MAP_FLAG_WRITE),
112 (true, true) => Err(errno!(EINVAL)),
113 }
114}
115
116impl KgslFile {
117 pub fn init() {
118 match Self::init_magma_logging() {
119 Ok(()) => log_info!("kgsl: magma logging enabled"),
120 Err(()) => log_warn!("kgsl: magma logging failed to initialize"),
121 };
122 }
123
124 fn init_magma_logging() -> Result<(), ()> {
125 let (client, server) = zx::Channel::create();
126 service_connect("/svc/fuchsia.logger.LogSink", server).map_err(|_| ())?;
127 return initialize_logging(client);
128 }
129
130 fn import_device(path: &str) -> Result<Device, zx::Status> {
131 let (client, server) = zx::Channel::create();
132 service_connect(&path, server)?;
133 let device = Device::from_channel(client).map_err(|_| zx::Status::INTERNAL)?;
134 let QueryOutput::Value(vendor_id) =
135 device.query(MAGMA_QUERY_VENDOR_ID).map_err(|_| zx::Status::INTERNAL)?
136 else {
137 return Err(zx::Status::INTERNAL);
138 };
139 let QueryOutput::Value(device_id) =
140 device.query(MAGMA_QUERY_DEVICE_ID).map_err(|_| zx::Status::INTERNAL)?
141 else {
142 return Err(zx::Status::INTERNAL);
143 };
144
145 log_info!(
146 "kgsl: magma device at {} is vendor {:#04x} device {:#04x}",
147 path,
148 vendor_id,
149 device_id
150 );
151 Ok(device)
152 }
153
154 pub fn new_file(
155 _current_task: &CurrentTask,
156 _dev: DeviceType,
157 _node: &FsNode,
158 _flags: OpenFlags,
159 ) -> Result<Box<dyn FileOps>, Errno> {
160 static INIT: Once = Once::new();
161 INIT.call_once(|| {
162 Self::init();
163 });
164 let mut devices = std::fs::read_dir("/svc/fuchsia.gpu.magma.Service")
165 .map_err(|_| errno!(ENXIO))?
166 .filter_map(|x| x.ok())
167 .filter_map(|entry| entry.path().join("device").into_os_string().into_string().ok())
168 .filter_map(|path| Self::import_device(&path).ok());
169 let device = devices.next().ok_or_else(|| errno!(ENXIO))?;
170 let QueryOutput::Buffer(adreno_kgsl_params_vmo) =
171 device.query(MAGMA_QCOM_ADRENO_QUERY_KGSL_PARAMS).map_err(|_| errno!(ENXIO))?
172 else {
173 return Err(errno!(ENXIO));
174 };
175
176 let adreno_kgsl_params = adreno_kgsl_params_vmo
177 .read_to_object::<AdrenoKgslParams>(0)
178 .map_err(|_| errno!(ENXIO))?;
179
180 let connection = device.create_connection().map_err(|_| errno!(ENXIO))?;
181
182 let mut allocator = RangeAllocator::create(adreno_kgsl_params.gpu_va64_size);
183
184 allocator.allocate(adreno_kgsl_params.gpu_secure_va_size).ok_or_else(|| errno!(ENOMEM))?;
186
187 let shadow_size = adreno_kgsl_params.device_shadow_size;
189 let shadow_buffer = connection.create_buffer(shadow_size).map_err(|_| errno!(ENOMEM))?;
190 allocator.allocate(shadow_size).ok_or_else(|| errno!(ENOMEM))?;
194 let shadow_gpuaddr = adreno_kgsl_params.gpu_secure_va_size;
195 shadow_buffer
196 .map(shadow_gpuaddr, 0, shadow_size, MAGMA_MAP_FLAG_READ | MAGMA_MAP_FLAG_WRITE)
197 .map_err(|_| errno!(ENOMEM))?;
198 let shadow = GpuObject {
199 buffer: shadow_buffer,
200 flags: adreno_kgsl_params.device_shadow_flags.into(),
201 size: shadow_size,
202 mmapsize: shadow_size,
203 gpuaddr: shadow_gpuaddr,
204 };
205 let shadow_properties = uapi::kgsl_shadowprop {
206 gpuaddr: shadow_gpuaddr.try_into().map_err(|_| errno!(ENXIO))?,
207 size: shadow_size.try_into().map_err(|_| errno!(ENXIO))?,
208 flags: adreno_kgsl_params.device_shadow_flags,
209 ..Default::default()
210 };
211
212 let shadow_id = 1;
213 let mut gpuobjs = HashMap::new();
214 gpuobjs.insert(shadow_id, shadow);
215
216 Ok(Box::new(Self {
217 device,
218 connection,
219 adreno_kgsl_params,
220 syncsources: Mutex::new(HashMap::new()),
221 next_syncsource_id: AtomicU32::new(1),
222 gpuobjs: Mutex::new(gpuobjs),
223 next_gpuobj_id: AtomicU32::new(shadow_id + 1),
224 allocator: Mutex::new(allocator),
225 shadow_properties,
226 contexts: Mutex::new(HashMap::new()),
227 next_context_id: AtomicU32::new(1),
228 }))
229 }
230
231 fn kgsl_device_getproperty(
232 &self,
233 current_task: &CurrentTask,
234 arg: SyscallArg,
235 ) -> Result<SyscallResult, Errno> {
236 let params_ref = maur::kgsl_device_getproperty::new(current_task, arg);
237 let params = current_task.read_multi_arch_object(params_ref)?;
238 kgsl_debug!("kgsl_device_getproperty {:?}", params);
239
240 let params_size: usize = params.sizebytes.try_into().map_err(|_| errno!(EINVAL))?;
241 match params.type_ {
244 uapi::KGSL_PROP_DEVICE_INFO => {
245 let prop_value = uapi::kgsl_devinfo {
246 device_id: self.adreno_kgsl_params.device_id,
247 chip_id: self.adreno_kgsl_params.chip_id,
248 mmu_enabled: self.adreno_kgsl_params.mmu_enabled,
249 gmem_gpubaseaddr: 0, gpu_id: self.adreno_kgsl_params.gpu_id,
251 gmem_sizebytes: self.adreno_kgsl_params.gmem_sizebytes,
252 ..Default::default()
253 };
254 kgsl_debug!("KGSL_PROP_DEVICE_INFO: {:?}", prop_value);
255 prop_value.write(¤t_task, params.value)
256 }
257 uapi::KGSL_PROP_DEVICE_SHADOW => {
258 let prop_value = self.shadow_properties;
259 kgsl_debug!("KGSL_PROP_DEVICE_SHADOW: {:?}", prop_value);
260 prop_value.write(¤t_task, params.value)
261 }
262 uapi::KGSL_PROP_UCHE_GMEM_VADDR => {
263 let prop_value = 0u32; kgsl_debug!("KGSL_PROP_UCHE_GMEM_VADDR: {:?}", prop_value);
265 prop_value.write(¤t_task, params.value)
266 }
267 uapi::KGSL_PROP_UCODE_VERSION => {
268 let prop_value = uapi::kgsl_ucode_version {
269 pfp: self.adreno_kgsl_params.ucode_version_pfp,
270 pm4: self.adreno_kgsl_params.ucode_version_pm4,
271 ..Default::default()
272 };
273 kgsl_debug!("KGSL_PROP_UCODE_VERSION: {:?}", prop_value);
274 prop_value.write(¤t_task, params.value)
275 }
276 uapi::KGSL_PROP_HIGHEST_BANK_BIT => {
277 let prop_value = self.adreno_kgsl_params.highest_bank_bit;
278 kgsl_debug!("KGSL_PROP_HIGHEST_BANK_BIT: {:?}", prop_value);
279 prop_value.write(¤t_task, params.value)
280 }
281 uapi::KGSL_PROP_DEVICE_BITNESS => {
282 let prop_value = self.adreno_kgsl_params.device_bitness;
283 kgsl_debug!("KGSL_PROP_DEVICE_BITNESS: {:?}", prop_value);
284 prop_value.write(¤t_task, params.value)
285 }
286 uapi::KGSL_PROP_DEVICE_QDSS_STM => {
287 let prop_value =
289 uapi::kgsl_qdss_stm_prop { gpuaddr: 0, size: 0, ..Default::default() };
290 kgsl_debug!("KGSL_PROP_DEVICE_QDSS_STM: {:?}", prop_value);
291 prop_value.write(¤t_task, params.value)
292 }
293 uapi::KGSL_PROP_MIN_ACCESS_LENGTH => {
294 let prop_value = self.adreno_kgsl_params.min_access_length;
295 kgsl_debug!("KGSL_PROP_MIN_ACCESS_LENGTH: {:?}", prop_value);
296 prop_value.write(¤t_task, params.value)
297 }
298 uapi::KGSL_PROP_UBWC_MODE => {
299 let prop_value = self.adreno_kgsl_params.ubwc_mode;
300 kgsl_debug!("KGSL_PROP_UBWC_MODE: {:?}", prop_value);
301 prop_value.write(¤t_task, params.value)
302 }
303 uapi::KGSL_PROP_DEVICE_QTIMER => {
304 let prop_value =
306 uapi::kgsl_qtimer_prop { gpuaddr: 0, size: 0, ..Default::default() };
307 kgsl_debug!("KGSL_PROP_DEVICE_QTIMER: {:?}", prop_value);
308 prop_value.write(¤t_task, params.value)
309 }
310 uapi::KGSL_PROP_SECURE_BUFFER_ALIGNMENT => {
311 let prop_value = self.adreno_kgsl_params.secure_buf_alignment;
312 kgsl_debug!("KGSL_PROP_SECURE_BUFFER_ALIGNMENT: {:?}", prop_value);
313 prop_value.write(¤t_task, params.value)
314 }
315 uapi::KGSL_PROP_SECURE_CTXT_SUPPORT => {
316 let prop_value = self.adreno_kgsl_params.secure_ctxt_support;
317 kgsl_debug!("KGSL_PROP_SECURE_CTXT_SUPPORT: {:?}", prop_value);
318 prop_value.write(¤t_task, params.value)
319 }
320 uapi::KGSL_PROP_SPEED_BIN => {
321 let prop_value = 0u64; kgsl_debug!("KGSL_PROP_SPEED_BIN: {:?}", prop_value);
323 prop_value.write(¤t_task, params.value)
324 }
325 uapi::KGSL_PROP_GAMING_BIN => {
326 kgsl_debug!("KGSL_PROP_GAMING_BIN returning EINVAL");
327 error!(EINVAL, "gaming bin unsupported")
328 }
329 uapi::KGSL_PROP_GPU_MODEL => {
330 if params_size < self.adreno_kgsl_params.gpu_model.len() {
331 return error!(EINVAL);
332 }
333 let prop_value = self.adreno_kgsl_params.gpu_model;
334 kgsl_debug!("KGSL_PROP_GPU_MODEL: {:?}", prop_value);
335 let result_ref = UserRef::from(UserAddress::from(params.value));
336 current_task.write_object(result_ref, &prop_value)?;
337 Ok(SUCCESS)
338 }
339 uapi::KGSL_PROP_VK_DEVICE_ID => {
340 let prop_value = self.adreno_kgsl_params.vk_device_id;
341 kgsl_debug!("KGSL_PROP_VK_DEVICE_ID: {:?}", prop_value);
342 prop_value.write(¤t_task, params.value)
343 }
344 uapi::KGSL_PROP_IS_LPAC_ENABLED => {
345 let prop_value = 0u32; kgsl_debug!("KGSL_PROP_IS_LPAC_ENABLED: {:?}", prop_value);
347 prop_value.write(¤t_task, params.value)
348 }
349 uapi::KGSL_PROP_GPU_VA64_SIZE => {
350 let prop_value = self.adreno_kgsl_params.gpu_va64_size;
351 kgsl_debug!("KGSL_PROP_GPU_VA64_SIZE: {:?}", prop_value);
352 prop_value.write(¤t_task, params.value)
353 }
354 uapi::KGSL_PROP_IS_RAYTRACING_ENABLED => {
355 let prop_value = 0u32; kgsl_debug!("KGSL_PROP_IS_RAYTRACING_ENABLED: {:?}", prop_value);
357 prop_value.write(¤t_task, params.value)
358 }
359 uapi::KGSL_PROP_IS_FASTBLEND_ENABLED => {
360 let prop_value = 0u32; kgsl_debug!("KGSL_PROP_IS_FASTBLEND_ENABLED: {:?}", prop_value);
362 prop_value.write(¤t_task, params.value)
363 }
364 uapi::KGSL_PROP_UCHE_TRAP_BASE => {
365 kgsl_debug!("KGSL_PROP_UCHE_TRAP_BASE returning EINVAL");
366 error!(EINVAL, "uche_trap_base unset")
367 }
368 uapi::KGSL_PROP_GPU_SECURE_VA_SIZE => {
369 let prop_value = self.adreno_kgsl_params.gpu_secure_va_size;
370 kgsl_debug!("KGSL_PROP_GPU_SECURE_VA_SIZE: {:?}", prop_value);
371 prop_value.write(¤t_task, params.value)
372 }
373 _ => {
374 track_stub!(TODO("https://fxbug.dev/393160668"), "kgsl property", params.type_);
375 log_error!("kgsl: unimplemented GetProperty type {}", kgsl_prop(params.type_));
376 error!(ENOTSUP)
377 }
378 }
379 }
380
381 fn kgsl_gpuobj_alloc(
382 &self,
383 current_task: &CurrentTask,
384 arg: SyscallArg,
385 ) -> Result<SyscallResult, Errno> {
386 let params_ref = maur::kgsl_gpuobj_alloc::new(current_task, arg);
387 let mut params = current_task.read_multi_arch_object(params_ref)?;
388 kgsl_debug!("kgsl_gpuobj_alloc {:?}", params);
389
390 let flags = KgslMemFlags::try_from(params.flags).map_err(|bits| {
391 log_error!("kgsl: unknown memory flags {:#x}", bits);
392 errno!(EINVAL)
393 })?;
394 if BUFFER_ALIGNMENT % (1 << flags.align_bits()) != 0 {
395 log_error!("kgsl: unsupported alignment {}", flags.align_bits());
396 return error!(ENOTSUP);
397 }
398
399 let buffer = self.connection.create_buffer(params.size).map_err(|_| errno!(ENOMEM))?;
400 let size = buffer.size();
401
402 let gpuaddr = self.allocator.lock().allocate(size).ok_or_else(|| errno!(ENOMEM))?;
403 buffer.map(gpuaddr, 0, size, map_flags(flags)?).map_err(|_| errno!(ENOMEM))?;
404
405 let id = self.next_gpuobj_id.fetch_add(1, Ordering::Relaxed);
406 if id == 0 {
407 log_error!("kgsl: gpuobj ids exhausted");
408 return error!(ENOMEM);
409 }
410
411 let gpuobj = GpuObject { buffer, flags: params.flags, size, mmapsize: size, gpuaddr };
412
413 self.gpuobjs.lock().insert(id, gpuobj);
414
415 params.size = size;
416 params.mmapsize = size;
417 params.id = id;
418
419 current_task.write_multi_arch_object(params_ref, params)?;
420 Ok(SUCCESS)
421 }
422
423 fn kgsl_gpuobj_free(
424 &self,
425 current_task: &CurrentTask,
426 arg: SyscallArg,
427 ) -> Result<SyscallResult, Errno> {
428 let params_ref = maur::kgsl_gpuobj_free::new(current_task, arg);
429 let params = current_task.read_multi_arch_object(params_ref)?;
430 kgsl_debug!("kgsl_gpuobj_free {:?}", params);
431
432 if let Entry::Occupied(entry) = self.gpuobjs.lock().entry(params.id) {
433 self.allocator.lock().free(entry.get().gpuaddr, entry.get().size);
434 entry.remove();
435 Ok(SUCCESS)
436 } else {
437 error!(EINVAL)
438 }
439 }
440
441 fn kgsl_gpuobj_info(
442 &self,
443 current_task: &CurrentTask,
444 arg: SyscallArg,
445 ) -> Result<SyscallResult, Errno> {
446 let params_ref = maur::kgsl_gpuobj_info::new(current_task, arg);
447 let mut params = current_task.read_multi_arch_object(params_ref)?;
448 kgsl_debug!("kgsl_gpuobj_info {:?}", params);
449
450 let gpuobjs = self.gpuobjs.lock();
451 let gpuobj = gpuobjs.get(¶ms.id).ok_or_else(|| errno!(EINVAL))?;
452
453 params.gpuaddr = gpuobj.gpuaddr;
454 params.size = gpuobj.size;
455 params.flags = gpuobj.flags;
456 params.va_len = gpuobj.size;
457 params.va_addr = 0;
458
459 current_task.write_multi_arch_object(params_ref, params)?;
460 Ok(SUCCESS)
461 }
462
463 fn kgsl_syncsource_create(
464 &self,
465 current_task: &CurrentTask,
466 arg: SyscallArg,
467 ) -> Result<SyscallResult, Errno> {
468 let params_ref = maur::kgsl_syncsource_create::new(current_task, arg);
469 let mut params = current_task.read_multi_arch_object(params_ref)?;
470 kgsl_debug!("kgsl_syncsource_create {:?}", params);
471
472 let semaphore = self.connection.create_semaphore().map_err(|_| errno!(ENOMEM))?;
473 let id = self.next_syncsource_id.fetch_add(1, Ordering::Relaxed);
474 if id == 0 {
475 log_error!("kgsl: ids exhausted");
478 return error!(ENOMEM);
479 }
480 self.syncsources.lock().insert(id, semaphore);
481
482 params.id = id;
483
484 current_task.write_multi_arch_object(params_ref, params)?;
485 Ok(SUCCESS)
486 }
487
488 fn kgsl_syncsource_destroy(
489 &self,
490 current_task: &CurrentTask,
491 arg: SyscallArg,
492 ) -> Result<SyscallResult, Errno> {
493 let params_ref = maur::kgsl_syncsource_destroy::new(current_task, arg);
494 let params = current_task.read_multi_arch_object(params_ref)?;
495 kgsl_debug!("kgsl_syncsource_destroy {:?}", params);
496
497 if self.syncsources.lock().remove(¶ms.id).is_some() {
498 Ok(SUCCESS)
499 } else {
500 error!(EINVAL)
501 }
502 }
503
504 fn kgsl_drawctxt_create(
505 &self,
506 current_task: &CurrentTask,
507 arg: SyscallArg,
508 ) -> Result<SyscallResult, Errno> {
509 let params_ref = maur::kgsl_drawctxt_create::new(current_task, arg);
510 let mut params = current_task.read_multi_arch_object(params_ref)?;
511 kgsl_debug!("kgsl_drawctxt_create {:?}", params);
512 let flags = KgslContextFlags::try_from(params.flags).map_err(|bits| {
513 log_error!("kgsl: unknown context flags {:#x}", bits);
514 errno!(EINVAL)
515 })?;
516 let context =
517 self.connection.create_context(flags.priority().into()).map_err(|_| errno!(ENXIO))?;
518 let id = self.next_context_id.fetch_add(1, Ordering::Relaxed);
519 if id == 0 {
520 log_error!("kgsl: ids exhausted");
523 return error!(ENOMEM);
524 }
525 self.contexts.lock().insert(id, context);
526 params.drawctxt_id = id;
527 current_task.write_multi_arch_object(params_ref, params)?;
528 Ok(SUCCESS)
529 }
530
531 fn kgsl_drawctxt_destroy(
532 &self,
533 current_task: &CurrentTask,
534 arg: SyscallArg,
535 ) -> Result<SyscallResult, Errno> {
536 let params_ref = maur::kgsl_drawctxt_destroy::new(current_task, arg);
537 let params = current_task.read_multi_arch_object(params_ref)?;
538 kgsl_debug!("kgsl_drawctxt_destroy {:?}", params);
539 if self.contexts.lock().remove(¶ms.drawctxt_id).is_some() {
540 Ok(SUCCESS)
541 } else {
542 error!(EINVAL)
543 }
544 }
545
546 fn kgsl_gpu_command(
547 &self,
548 current_task: &CurrentTask,
549 arg: SyscallArg,
550 ) -> Result<SyscallResult, Errno> {
551 let params_ref = maur::kgsl_gpu_command::new(current_task, arg);
552 let params = current_task.read_multi_arch_object(params_ref)?;
553 kgsl_debug!("kgsl_gpu_command {:?}", params);
554 let contexts = self.contexts.lock();
555 let context = contexts.get(¶ms.context_id).ok_or_else(|| errno!(EINVAL))?;
556
557 let cmds = current_task.read_objects_to_vec::<kgsl_command_object>(
558 UserRef::from(UserAddress::from(params.cmdlist)),
559 params.numcmds as usize,
560 )?;
561 kgsl_debug!("kgsl_gpu_command cmds {:?}", cmds);
562 let objs = current_task.read_objects_to_vec::<kgsl_command_object>(
563 UserRef::from(UserAddress::from(params.objlist)),
564 params.numobjs as usize,
565 )?;
566 kgsl_debug!("kgsl_gpu_command objs {:?}", objs);
567 let syncs = current_task.read_objects_to_vec::<kgsl_command_syncpoint>(
568 UserRef::from(UserAddress::from(params.synclist)),
569 params.numsyncs as usize,
570 )?;
571 kgsl_debug!("kgsl_gpu_command syncs {:?}", syncs);
572 if syncs.len() > 0 {
573 log_error!("kgsl: syncs not supported yet");
575 return error!(ENOTSUP);
576 }
577
578 if params.flags != 0 {
579 let flags = KgslCmdBatchFlags::try_from(params.flags).map_err(|bits| {
580 log_error!("kgsl: unknown command flags {:#x}", bits);
581 errno!(EINVAL)
582 })?;
583 log_warn!("kgsl: unsupported flags {:?}", flags);
584 }
585
586 let gpuobjs = self.gpuobjs.lock();
587
588 let to_exec_resources = |objects: &[kgsl_command_object],
589 kind: &str|
590 -> Result<Vec<kgsl_libmagma::ExecResource>, Errno> {
591 objects
597 .iter()
598 .map(|obj| {
599 let gpuobj = gpuobjs
600 .values()
601 .find(|o| obj.gpuaddr >= o.gpuaddr && obj.gpuaddr < o.gpuaddr + o.size)
602 .ok_or_else(|| {
603 log_error!("kgsl: {} gpuaddr {:#x} not found", kind, obj.gpuaddr);
604 errno!(EINVAL)
605 })?;
606 Ok(kgsl_libmagma::ExecResource {
607 buffer: gpuobj.buffer.clone(),
608 offset: (obj.gpuaddr - gpuobj.gpuaddr) + obj.offset,
609 length: obj.size,
610 })
611 })
612 .collect()
613 };
614
615 let magma_resources = to_exec_resources(&objs, "resource")?;
616 let magma_command_buffers = to_exec_resources(&cmds, "command")?;
617
618 context
619 .execute_command(magma_command_buffers, magma_resources, vec![], vec![], 0)
620 .map_err(|_| errno!(EINVAL))?;
621
622 Ok(SUCCESS)
623 }
624}
625
626impl Drop for KgslFile {
627 fn drop(&mut self) {}
628}
629
630impl FileOps for KgslFile {
631 fileops_impl_dataless!();
632 fileops_impl_nonseekable!();
633 fileops_impl_noop_sync!();
634
635 fn ioctl(
636 &self,
637 _locked: &mut Locked<Unlocked>,
638 _file: &FileObject,
639 current_task: &CurrentTask,
640 request: u32,
641 arg: SyscallArg,
642 ) -> Result<SyscallResult, Errno> {
643 const IOCTL_KGSL_ENABLE: u32 = 42;
646 if request == IOCTL_KGSL_ENABLE {
647 if cfg!(not(feature = "starnix-kgsl-enable")) {
648 log_info!("kgsl: suppressing further use of kgsl");
649 return error!(ENXIO);
650 }
651 return Ok(SUCCESS);
652 }
653 match crate::util::canonicalize_ioctl_request(current_task, request) {
654 uapi::IOCTL_KGSL_DEVICE_GETPROPERTY => self.kgsl_device_getproperty(current_task, arg),
655 uapi::IOCTL_KGSL_GPUOBJ_ALLOC => self.kgsl_gpuobj_alloc(current_task, arg),
656 uapi::IOCTL_KGSL_GPUOBJ_FREE => self.kgsl_gpuobj_free(current_task, arg),
657 uapi::IOCTL_KGSL_GPUOBJ_INFO => self.kgsl_gpuobj_info(current_task, arg),
658 uapi::IOCTL_KGSL_SYNCSOURCE_CREATE => self.kgsl_syncsource_create(current_task, arg),
659 uapi::IOCTL_KGSL_SYNCSOURCE_DESTROY => self.kgsl_syncsource_destroy(current_task, arg),
660 uapi::IOCTL_KGSL_DRAWCTXT_CREATE => self.kgsl_drawctxt_create(current_task, arg),
661 uapi::IOCTL_KGSL_DRAWCTXT_DESTROY => self.kgsl_drawctxt_destroy(current_task, arg),
662 uapi::IOCTL_KGSL_GPU_COMMAND => self.kgsl_gpu_command(current_task, arg),
663 _ => {
664 track_stub!(TODO("https://fxbug.dev/393160668"), "kgsl ioctl", request);
665 log_error!("kgsl: unimplemented ioctl {}", ioctl_kgsl(request));
666 error!(ENOTSUP)
667 }
668 }
669 }
670
671 fn mmap(
672 &self,
673 _locked: &mut Locked<starnix_sync::FileOpsCore>,
674 file: &FileObject,
675 current_task: &CurrentTask,
676 addr: starnix_core::mm::DesiredAddress,
677 memory_offset: u64, length: usize,
679 prot_flags: starnix_core::mm::ProtectionFlags,
680 mapping_options: starnix_core::mm::MappingOptions,
681 _filename: starnix_core::vfs::NamespaceNode,
682 ) -> Result<UserAddress, Errno> {
683 kgsl_debug!("mmap {:?} {:?} {:?} {:?}", addr, memory_offset, length, prot_flags);
684 let id = (memory_offset / *PAGE_SIZE) as u32;
685 let gpuobjs = self.gpuobjs.lock();
686 let gpuobj = gpuobjs.get(&id).ok_or_else(|| errno!(EINVAL))?;
687 if length as u64 > gpuobj.mmapsize {
688 return error!(EINVAL);
689 }
690 let handle = gpuobj.buffer.get_handle().map_err(|_| errno!(ENXIO))?;
691 let vmo = zx::Vmo::from(handle);
692 let memory = Arc::new(MemoryObject::from(vmo).with_zx_name(b"starnix:kgsl"));
693 current_task.mm()?.map_memory(
695 addr,
696 memory,
697 0,
698 length,
699 prot_flags,
700 file.max_access_for_memory_mapping(),
701 mapping_options,
702 MappingName::None,
703 )
704 }
705}