99
1010use crate :: debug:: * ;
1111use crate :: driver:: AsahiDevice ;
12- use crate :: { alloc, buffer, driver, gem, mmu, queue} ;
12+ use crate :: { alloc, buffer, driver, gem, mmu, queue, util :: RangeExt } ;
1313use core:: mem:: MaybeUninit ;
14+ use core:: ops:: Range ;
1415use kernel:: dma_fence:: RawDmaFence ;
1516use kernel:: drm:: gem:: BaseObject ;
1617use kernel:: error:: code:: * ;
@@ -30,16 +31,29 @@ struct Vm {
3031 ualloc : Arc < Mutex < alloc:: DefaultAllocator > > ,
3132 ualloc_priv : Arc < Mutex < alloc:: DefaultAllocator > > ,
3233 vm : mmu:: Vm ,
34+ kernel_range : Range < u64 > ,
3335 _dummy_mapping : mmu:: KernelMapping ,
3436}
3537
3638impl Drop for Vm {
3739 fn drop ( & mut self ) {
3840 // When the user Vm is dropped, unmap everything in the user range
39- if self
40- . vm
41- . unmap_range ( mmu:: IOVA_USER_BASE , VM_USER_END )
42- . is_err ( )
41+ let left_range = VM_USER_RANGE . start ..self . kernel_range . start ;
42+ let right_range = self . kernel_range . end ..VM_USER_RANGE . end ;
43+
44+ if !left_range. is_empty ( )
45+ && self
46+ . vm
47+ . unmap_range ( left_range. start , left_range. range ( ) )
48+ . is_err ( )
49+ {
50+ pr_err ! ( "Vm::Drop: vm.unmap_range() failed\n " ) ;
51+ }
52+ if !right_range. is_empty ( )
53+ && self
54+ . vm
55+ . unmap_range ( right_range. start , right_range. range ( ) )
56+ . is_err ( )
4357 {
4458 pr_err ! ( "Vm::Drop: vm.unmap_range() failed\n " ) ;
4559 }
@@ -155,23 +169,11 @@ pub(crate) struct File {
155169/// Convenience type alias for our DRM `File` type.
156170pub ( crate ) type DrmFile = drm:: file:: File < File > ;
157171
158- /// Start address of the 32-bit USC address space.
159- const VM_SHADER_START : u64 = 0x11_00000000 ;
160- /// End address of the 32-bit USC address space.
161- const VM_SHADER_END : u64 = 0x11_ffffffff ;
162- /// Start address of the general user mapping region.
163- const VM_USER_START : u64 = 0x20_00000000 ;
164- /// End address of the general user mapping region.
165- const VM_USER_END : u64 = 0x6f_ffff0000 ;
166-
167- /// Start address of the kernel-managed GPU-only mapping region.
168- const VM_DRV_GPU_START : u64 = 0x70_00000000 ;
169- /// End address of the kernel-managed GPU-only mapping region.
170- const VM_DRV_GPU_END : u64 = 0x70_ffffffff ;
171- /// Start address of the kernel-managed GPU/FW shared mapping region.
172- const VM_DRV_GPUFW_START : u64 = 0x71_00000000 ;
173- /// End address of the kernel-managed GPU/FW shared mapping region.
174- const VM_DRV_GPUFW_END : u64 = 0x71_ffffffff ;
172+ /// Available VM range for the user
173+ const VM_USER_RANGE : Range < u64 > = mmu:: IOVA_USER_USABLE_RANGE ;
174+
175+ /// Minimum reserved AS for kernel mappings
176+ const VM_KERNEL_MIN_SIZE : u64 = 0x20000000 ;
175177
176178impl drm:: file:: DriverFile for File {
177179 type Driver = driver:: AsahiDriver ;
@@ -247,10 +249,11 @@ impl File {
247249
248250 vm_page_size : mmu:: UAT_PGSZ as u32 ,
249251 pad1 : 0 ,
250- vm_user_start : VM_USER_START ,
251- vm_user_end : VM_USER_END ,
252- vm_shader_start : VM_SHADER_START ,
253- vm_shader_end : VM_SHADER_END ,
252+ vm_user_start : VM_USER_RANGE . start ,
253+ vm_user_end : VM_USER_RANGE . end ,
254+ vm_usc_start : 0 , // Arbitrary
255+ vm_usc_end : 0 ,
256+ vm_kernel_min_size : VM_KERNEL_MIN_SIZE ,
254257
255258 max_syncs_per_submission : 0 ,
256259 max_commands_per_submission : MAX_COMMANDS_PER_SUBMISSION ,
@@ -299,9 +302,25 @@ impl File {
299302 return Err ( EINVAL ) ;
300303 }
301304
305+ let kernel_range = data. kernel_start ..data. kernel_end ;
306+
307+ // Validate requested kernel range
308+ if !VM_USER_RANGE . is_superset ( kernel_range. clone ( ) )
309+ || kernel_range. range ( ) < VM_KERNEL_MIN_SIZE
310+ || kernel_range. start & ( mmu:: UAT_PGMSK as u64 ) != 0
311+ || kernel_range. end & ( mmu:: UAT_PGMSK as u64 ) != 0
312+ {
313+ cls_pr_debug ! ( Errors , "vm_create: Invalid kernel range\n " ) ;
314+ return Err ( EINVAL ) ;
315+ }
316+
317+ let kernel_half_size = ( kernel_range. range ( ) >> 1 ) & !( mmu:: UAT_PGMSK as u64 ) ;
318+ let kernel_gpu_range = kernel_range. start ..( kernel_range. start + kernel_half_size) ;
319+ let kernel_gpufw_range = kernel_gpu_range. end ..kernel_range. end ;
320+
302321 let gpu = & device. data ( ) . gpu ;
303322 let file_id = file. inner ( ) . id ;
304- let vm = gpu. new_vm ( ) ?;
323+ let vm = gpu. new_vm ( kernel_range . clone ( ) ) ?;
305324
306325 let resv = file. inner ( ) . vms ( ) . reserve ( ) ?;
307326 let id: u32 = resv. index ( ) . try_into ( ) ?;
@@ -316,7 +335,7 @@ impl File {
316335 let ualloc = Arc :: pin_init ( Mutex :: new ( alloc:: DefaultAllocator :: new (
317336 device,
318337 & vm,
319- VM_DRV_GPU_START .. VM_DRV_GPU_END ,
338+ kernel_gpu_range ,
320339 buffer:: PAGE_SIZE ,
321340 mmu:: PROT_GPU_SHARED_RW ,
322341 512 * 1024 ,
@@ -327,7 +346,7 @@ impl File {
327346 let ualloc_priv = Arc :: pin_init ( Mutex :: new ( alloc:: DefaultAllocator :: new (
328347 device,
329348 & vm,
330- VM_DRV_GPUFW_START .. VM_DRV_GPUFW_END ,
349+ kernel_gpufw_range ,
331350 buffer:: PAGE_SIZE ,
332351 mmu:: PROT_GPU_FW_PRIV_RW ,
333352 64 * 1024 ,
@@ -352,6 +371,7 @@ impl File {
352371 ualloc,
353372 ualloc_priv,
354373 vm,
374+ kernel_range,
355375 _dummy_mapping : dummy_mapping,
356376 } ) ?) ?;
357377
@@ -512,47 +532,17 @@ impl File {
512532 let bo = gem:: lookup_handle ( file, data. handle ) ?;
513533
514534 let start = data. addr ;
515- let end = data. addr + data. range - 1 ;
516-
517- if ( VM_SHADER_START ..=VM_SHADER_END ) . contains ( & start) {
518- if !( VM_SHADER_START ..=VM_SHADER_END ) . contains ( & end) {
519- cls_pr_debug ! (
520- Errors ,
521- "gem_bind: Invalid map range {:#x}..{:#x} (straddles shader range)\n " ,
522- start,
523- end
524- ) ;
525- return Err ( EINVAL ) ; // Invalid map range
526- }
527- } else if ( VM_USER_START ..=VM_USER_END ) . contains ( & start) {
528- if !( VM_USER_START ..=VM_USER_END ) . contains ( & end) {
529- cls_pr_debug ! (
530- Errors ,
531- "gem_bind: Invalid map range {:#x}..{:#x} (straddles user range)\n " ,
532- start,
533- end
534- ) ;
535- return Err ( EINVAL ) ; // Invalid map range
536- }
537- } else {
538- cls_pr_debug ! (
539- Errors ,
540- "gem_bind: Invalid map range {:#x}..{:#x}\n " ,
541- start,
542- end
543- ) ;
544- return Err ( EINVAL ) ; // Invalid map range
545- }
535+ let end = data. addr . checked_add ( data. range ) . ok_or ( EINVAL ) ?;
536+ let range = start..end;
546537
547- // Just in case
548- if end >= VM_DRV_GPU_START {
538+ if !VM_USER_RANGE . is_superset ( range. clone ( ) ) {
549539 cls_pr_debug ! (
550540 Errors ,
551- "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n " ,
541+ "gem_bind: Invalid map range {:#x}..{:#x} (not contained in user range)\n " ,
552542 start,
553543 end
554544 ) ;
555- return Err ( EINVAL ) ;
545+ return Err ( EINVAL ) ; // Invalid map range
556546 }
557547
558548 let prot = if data. flags & uapi:: ASAHI_BIND_READ != 0 {
@@ -572,15 +562,26 @@ impl File {
572562 return Err ( EINVAL ) ; // Must specify one of ASAHI_BIND_{READ,WRITE}
573563 } ;
574564
575- // Clone it immediately so we aren't holding the XArray lock
576- let vm = file
565+ let guard = file
577566 . inner ( )
578567 . vms ( )
579568 . get ( data. vm_id . try_into ( ) ?)
580- . ok_or ( ENOENT ) ?
581- . borrow ( )
582- . vm
583- . clone ( ) ;
569+ . ok_or ( ENOENT ) ?;
570+
571+ // Clone it immediately so we aren't holding the XArray lock
572+ let vm = guard. borrow ( ) . vm . clone ( ) ;
573+ let kernel_range = guard. borrow ( ) . kernel_range . clone ( ) ;
574+ core:: mem:: drop ( guard) ;
575+
576+ if kernel_range. overlaps ( range) {
577+ cls_pr_debug ! (
578+ Errors ,
579+ "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n " ,
580+ start,
581+ end
582+ ) ;
583+ return Err ( EINVAL ) ;
584+ }
584585
585586 vm. bind_object ( & bo. gem , data. addr , data. range , data. offset , prot) ?;
586587
0 commit comments