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