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