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 }
@@ -153,23 +167,11 @@ pub(crate) struct File {
153167/// Convenience type alias for our DRM `File` type.
154168pub ( crate ) type DrmFile = drm:: file:: File < File > ;
155169
156- /// Start address of the 32-bit USC address space.
157- const VM_SHADER_START : u64 = 0x11_00000000 ;
158- /// End address of the 32-bit USC address space.
159- const VM_SHADER_END : u64 = 0x11_ffffffff ;
160- /// Start address of the general user mapping region.
161- const VM_USER_START : u64 = 0x20_00000000 ;
162- /// End address of the general user mapping region.
163- const VM_USER_END : u64 = 0x6f_ffff0000 ;
164-
165- /// Start address of the kernel-managed GPU-only mapping region.
166- const VM_DRV_GPU_START : u64 = 0x70_00000000 ;
167- /// End address of the kernel-managed GPU-only mapping region.
168- const VM_DRV_GPU_END : u64 = 0x70_ffffffff ;
169- /// Start address of the kernel-managed GPU/FW shared mapping region.
170- const VM_DRV_GPUFW_START : u64 = 0x71_00000000 ;
171- /// End address of the kernel-managed GPU/FW shared mapping region.
172- const VM_DRV_GPUFW_END : u64 = 0x71_ffffffff ;
170+ /// Available VM range for the user
171+ const VM_USER_RANGE : Range < u64 > = mmu:: IOVA_USER_USABLE_RANGE ;
172+
173+ /// Minimum reserved AS for kernel mappings
174+ const VM_KERNEL_MIN_SIZE : u64 = 0x20000000 ;
173175
174176impl drm:: file:: DriverFile for File {
175177 type Driver = driver:: AsahiDriver ;
@@ -248,10 +250,11 @@ impl File {
248250
249251 vm_page_size : mmu:: UAT_PGSZ as u32 ,
250252 pad1 : 0 ,
251- vm_user_start : VM_USER_START ,
252- vm_user_end : VM_USER_END ,
253- vm_shader_start : VM_SHADER_START ,
254- vm_shader_end : VM_SHADER_END ,
253+ vm_user_start : VM_USER_RANGE . start ,
254+ vm_user_end : VM_USER_RANGE . end ,
255+ vm_usc_start : 0 , // Arbitrary
256+ vm_usc_end : 0 ,
257+ vm_kernel_min_size : VM_KERNEL_MIN_SIZE ,
255258
256259 max_syncs_per_submission : 0 ,
257260 max_commands_per_submission : MAX_COMMANDS_PER_SUBMISSION ,
@@ -300,9 +303,25 @@ impl File {
300303 return Err ( EINVAL ) ;
301304 }
302305
306+ let kernel_range = data. kernel_start ..data. kernel_end ;
307+
308+ // Validate requested kernel range
309+ if !VM_USER_RANGE . is_superset ( kernel_range. clone ( ) )
310+ || kernel_range. range ( ) < VM_KERNEL_MIN_SIZE
311+ || kernel_range. start & ( mmu:: UAT_PGMSK as u64 ) != 0
312+ || kernel_range. end & ( mmu:: UAT_PGMSK as u64 ) != 0
313+ {
314+ cls_pr_debug ! ( Errors , "vm_create: Invalid kernel range\n " ) ;
315+ return Err ( EINVAL ) ;
316+ }
317+
318+ let kernel_half_size = ( kernel_range. range ( ) >> 1 ) & !( mmu:: UAT_PGMSK as u64 ) ;
319+ let kernel_gpu_range = kernel_range. start ..( kernel_range. start + kernel_half_size) ;
320+ let kernel_gpufw_range = kernel_gpu_range. end ..kernel_range. end ;
321+
303322 let gpu = & device. data ( ) . gpu ;
304323 let file_id = file. inner ( ) . id ;
305- let vm = gpu. new_vm ( ) ?;
324+ let vm = gpu. new_vm ( kernel_range . clone ( ) ) ?;
306325
307326 let resv = file. inner ( ) . vms ( ) . reserve ( ) ?;
308327 let id: u32 = resv. index ( ) . try_into ( ) ?;
@@ -318,7 +337,7 @@ impl File {
318337 Mutex :: new ( alloc:: DefaultAllocator :: new (
319338 device,
320339 & vm,
321- VM_DRV_GPU_START .. VM_DRV_GPU_END ,
340+ kernel_gpu_range ,
322341 buffer:: PAGE_SIZE ,
323342 mmu:: PROT_GPU_SHARED_RW ,
324343 512 * 1024 ,
@@ -332,7 +351,7 @@ impl File {
332351 Mutex :: new ( alloc:: DefaultAllocator :: new (
333352 device,
334353 & vm,
335- VM_DRV_GPUFW_START .. VM_DRV_GPUFW_END ,
354+ kernel_gpufw_range ,
336355 buffer:: PAGE_SIZE ,
337356 mmu:: PROT_GPU_FW_PRIV_RW ,
338357 64 * 1024 ,
@@ -360,6 +379,7 @@ impl File {
360379 ualloc,
361380 ualloc_priv,
362381 vm,
382+ kernel_range,
363383 _dummy_mapping : dummy_mapping,
364384 } ,
365385 GFP_KERNEL ,
@@ -522,47 +542,17 @@ impl File {
522542 let bo = gem:: lookup_handle ( file, data. handle ) ?;
523543
524544 let start = data. addr ;
525- let end = data. addr + data. range - 1 ;
526-
527- if ( VM_SHADER_START ..=VM_SHADER_END ) . contains ( & start) {
528- if !( VM_SHADER_START ..=VM_SHADER_END ) . contains ( & end) {
529- cls_pr_debug ! (
530- Errors ,
531- "gem_bind: Invalid map range {:#x}..{:#x} (straddles shader range)\n " ,
532- start,
533- end
534- ) ;
535- return Err ( EINVAL ) ; // Invalid map range
536- }
537- } else if ( VM_USER_START ..=VM_USER_END ) . contains ( & start) {
538- if !( VM_USER_START ..=VM_USER_END ) . contains ( & end) {
539- cls_pr_debug ! (
540- Errors ,
541- "gem_bind: Invalid map range {:#x}..{:#x} (straddles user range)\n " ,
542- start,
543- end
544- ) ;
545- return Err ( EINVAL ) ; // Invalid map range
546- }
547- } else {
548- cls_pr_debug ! (
549- Errors ,
550- "gem_bind: Invalid map range {:#x}..{:#x}\n " ,
551- start,
552- end
553- ) ;
554- return Err ( EINVAL ) ; // Invalid map range
555- }
545+ let end = data. addr . checked_add ( data. range ) . ok_or ( EINVAL ) ?;
546+ let range = start..end;
556547
557- // Just in case
558- if end >= VM_DRV_GPU_START {
548+ if !VM_USER_RANGE . is_superset ( range. clone ( ) ) {
559549 cls_pr_debug ! (
560550 Errors ,
561- "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n " ,
551+ "gem_bind: Invalid map range {:#x}..{:#x} (not contained in user range)\n " ,
562552 start,
563553 end
564554 ) ;
565- return Err ( EINVAL ) ;
555+ return Err ( EINVAL ) ; // Invalid map range
566556 }
567557
568558 let prot = if data. flags & uapi:: ASAHI_BIND_READ != 0 {
@@ -582,15 +572,26 @@ impl File {
582572 return Err ( EINVAL ) ; // Must specify one of ASAHI_BIND_{READ,WRITE}
583573 } ;
584574
585- // Clone it immediately so we aren't holding the XArray lock
586- let vm = file
575+ let guard = file
587576 . inner ( )
588577 . vms ( )
589578 . get ( data. vm_id . try_into ( ) ?)
590- . ok_or ( ENOENT ) ?
591- . borrow ( )
592- . vm
593- . clone ( ) ;
579+ . ok_or ( ENOENT ) ?;
580+
581+ // Clone it immediately so we aren't holding the XArray lock
582+ let vm = guard. borrow ( ) . vm . clone ( ) ;
583+ let kernel_range = guard. borrow ( ) . kernel_range . clone ( ) ;
584+ core:: mem:: drop ( guard) ;
585+
586+ if kernel_range. overlaps ( range) {
587+ cls_pr_debug ! (
588+ Errors ,
589+ "gem_bind: Invalid map range {:#x}..{:#x} (intrudes in kernel range)\n " ,
590+ start,
591+ end
592+ ) ;
593+ return Err ( EINVAL ) ;
594+ }
594595
595596 vm. bind_object ( & bo. gem , data. addr , data. range , data. offset , prot) ?;
596597
0 commit comments