@@ -965,6 +965,20 @@ fn handle_virgl_op(cmd: &FbDrawCmd) -> SyscallResult {
965965
966966 SyscallResult :: Ok ( count as u64 )
967967 }
968+ 20 => {
969+ // MapCompositorTexture: map COMPOSITE_TEX backing pages into caller's
970+ // address space for zero-copy compositor writes.
971+ // p1/p2 = output pointer (lo/hi) for mapped address (u64)
972+ // Returns: packed (width << 32 | height) on success.
973+ #[ cfg( target_arch = "aarch64" ) ]
974+ {
975+ handle_map_compositor_texture ( cmd)
976+ }
977+ #[ cfg( not( target_arch = "aarch64" ) ) ]
978+ {
979+ SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 )
980+ }
981+ }
968982 _ => {
969983 crate :: serial_println!( "[virgl-op] UNKNOWN op={}" , cmd. op) ;
970984 SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 )
@@ -973,14 +987,23 @@ fn handle_virgl_op(cmd: &FbDrawCmd) -> SyscallResult {
973987}
974988
975989/// Descriptor for multi-window GPU compositing (passed from userspace).
990+ ///
991+ /// bg_dirty modes:
992+ /// 0 = no background change (cursor/frame-pacing only)
993+ /// 1 = full background upload (entire buffer changed)
994+ /// 2 = partial background upload (only dirty_rect region changed)
976995#[ cfg( target_arch = "aarch64" ) ]
977996#[ repr( C ) ]
978997struct CompositeWindowsDesc {
979998 bg_pixels_ptr : u64 ,
980999 bg_width : u32 ,
9811000 bg_height : u32 ,
9821001 bg_dirty : u32 ,
983- _reserved : u32 ,
1002+ num_dirty_rects : u32 ,
1003+ dirty_x : u32 ,
1004+ dirty_y : u32 ,
1005+ dirty_w : u32 ,
1006+ dirty_h : u32 ,
9841007}
9851008
9861009/// Handle multi-window GPU compositing (op=16).
@@ -991,11 +1014,27 @@ struct CompositeWindowsDesc {
9911014fn handle_composite_windows ( desc_ptr : u64 ) -> SyscallResult {
9921015 let desc: CompositeWindowsDesc = unsafe { core:: ptr:: read ( desc_ptr as * const CompositeWindowsDesc ) } ;
9931016
994- if desc. bg_width == 0 || desc. bg_height == 0 || desc. bg_width > 4096 || desc. bg_height > 4096 {
995- return SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 ) ;
996- }
1017+ // When bg_pixels_ptr=0 (direct-mapped compositor), use COMPOSITE_TEX dimensions
1018+ let ( bg_width, bg_height) = if desc. bg_pixels_ptr == 0 {
1019+ match crate :: drivers:: virtio:: gpu_pci:: compositor_texture_info ( ) {
1020+ Some ( ( _phys, _pages, w, h) ) => ( w, h) ,
1021+ None => return SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 ) ,
1022+ }
1023+ } else {
1024+ if desc. bg_width == 0 || desc. bg_height == 0 || desc. bg_width > 4096 || desc. bg_height > 4096 {
1025+ return SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 ) ;
1026+ }
1027+ ( desc. bg_width , desc. bg_height )
1028+ } ;
9971029
9981030 let bg_dirty = desc. bg_dirty != 0 ;
1031+ let dirty_rect = if desc. bg_dirty == 2 && desc. num_dirty_rects > 0
1032+ && desc. dirty_w > 0 && desc. dirty_h > 0
1033+ {
1034+ Some ( ( desc. dirty_x , desc. dirty_y , desc. dirty_w , desc. dirty_h ) )
1035+ } else {
1036+ None
1037+ } ;
9991038
10001039 // Fast path: quick dirty check under lock — no heap allocs if nothing changed
10011040 if !bg_dirty {
@@ -1058,7 +1097,7 @@ fn handle_composite_windows(desc_ptr: u64) -> SyscallResult {
10581097 }
10591098
10601099 let bg_pixels = if desc. bg_pixels_ptr != 0 && desc. bg_pixels_ptr < USER_SPACE_MAX {
1061- let pixel_count = ( desc . bg_width as usize ) * ( desc . bg_height as usize ) ;
1100+ let pixel_count = ( bg_width as usize ) * ( bg_height as usize ) ;
10621101 let end = desc. bg_pixels_ptr + ( pixel_count as u64 ) * 4 ;
10631102 if end > USER_SPACE_MAX {
10641103 return SyscallResult :: Err ( super :: ErrorCode :: Fault as u64 ) ;
@@ -1108,7 +1147,7 @@ fn handle_composite_windows(desc_ptr: u64) -> SyscallResult {
11081147 } ;
11091148
11101149 let result = match crate :: drivers:: virtio:: gpu_pci:: virgl_composite_windows (
1111- bg_pixels, desc . bg_width , desc . bg_height , bg_dirty, None , & windows,
1150+ bg_pixels, bg_width, bg_height, bg_dirty, dirty_rect , & windows,
11121151 ) {
11131152 Ok ( ( ) ) => SyscallResult :: Ok ( 0 ) ,
11141153 Err ( e) => {
@@ -1279,6 +1318,99 @@ fn handle_create_window_buffer(width: u32, height: u32, out_addr_ptr: u64) -> Sy
12791318 SyscallResult :: Ok ( buffer_id as u64 )
12801319}
12811320
1321+ /// Handle map_compositor_texture: map COMPOSITE_TEX backing pages into the
1322+ /// calling process's address space (read/write). This allows BWM to write
1323+ /// pixels directly into the GPU texture backing, eliminating the kernel-side
1324+ /// copy in virgl_composite_windows Phase A.
1325+ #[ cfg( target_arch = "aarch64" ) ]
1326+ fn handle_map_compositor_texture ( cmd : & FbDrawCmd ) -> SyscallResult {
1327+ use crate :: memory:: vma:: { MmapFlags , Protection , Vma } ;
1328+ use crate :: syscall:: memory_common:: {
1329+ get_current_thread_id, prot_to_page_flags, flush_tlb, round_down_to_page, PAGE_SIZE ,
1330+ } ;
1331+ use crate :: memory:: arch_stub:: { Page , Size4KiB , VirtAddr } ;
1332+
1333+ let out_ptr = ( cmd. p1 as u32 as u64 ) | ( ( cmd. p2 as u32 as u64 ) << 32 ) ;
1334+ if out_ptr == 0 || out_ptr >= USER_SPACE_MAX {
1335+ return SyscallResult :: Err ( super :: ErrorCode :: Fault as u64 ) ;
1336+ }
1337+
1338+ // Get compositor texture info from GPU driver
1339+ let ( phys_base, num_pages, tex_w, tex_h) =
1340+ match crate :: drivers:: virtio:: gpu_pci:: compositor_texture_info ( ) {
1341+ Some ( info) => info,
1342+ None => return SyscallResult :: Err ( super :: ErrorCode :: InvalidArgument as u64 ) ,
1343+ } ;
1344+
1345+ // Get current process
1346+ let current_thread_id = match get_current_thread_id ( ) {
1347+ Some ( id) => id,
1348+ None => return SyscallResult :: Err ( super :: ErrorCode :: NoSuchProcess as u64 ) ,
1349+ } ;
1350+
1351+ let mut manager_guard = crate :: process:: manager ( ) ;
1352+ let manager = match * manager_guard {
1353+ Some ( ref mut m) => m,
1354+ None => return SyscallResult :: Err ( super :: ErrorCode :: NoSuchProcess as u64 ) ,
1355+ } ;
1356+
1357+ let ( _pid, process) = match manager. find_process_by_thread_mut ( current_thread_id) {
1358+ Some ( p) => p,
1359+ None => return SyscallResult :: Err ( super :: ErrorCode :: NoSuchProcess as u64 ) ,
1360+ } ;
1361+
1362+ // Allocate virtual address range from mmap hint
1363+ let total_size = ( num_pages as u64 ) * PAGE_SIZE ;
1364+ let new_addr = round_down_to_page ( process. mmap_hint . saturating_sub ( total_size) ) ;
1365+ if new_addr < 0x1000_0000 {
1366+ return SyscallResult :: Err ( super :: ErrorCode :: OutOfMemory as u64 ) ;
1367+ }
1368+ process. mmap_hint = new_addr;
1369+
1370+ let page_table = match process. page_table . as_mut ( ) {
1371+ Some ( pt) => pt,
1372+ None => return SyscallResult :: Err ( super :: ErrorCode :: OutOfMemory as u64 ) ,
1373+ } ;
1374+
1375+ // Map each physical page of COMPOSITE_TEX into the process
1376+ let page_flags = prot_to_page_flags ( Protection :: from_bits_truncate ( 3 ) ) ; // READ | WRITE
1377+ for i in 0 ..num_pages as usize {
1378+ let frame_phys = phys_base + ( i as u64 ) * PAGE_SIZE ;
1379+ let frame = crate :: memory:: arch_stub:: PhysFrame :: < Size4KiB > :: containing_address (
1380+ crate :: memory:: arch_stub:: PhysAddr :: new ( frame_phys) ,
1381+ ) ;
1382+ let page_addr = new_addr + ( i as u64 ) * PAGE_SIZE ;
1383+ let page = Page :: < Size4KiB > :: containing_address ( VirtAddr :: new ( page_addr) ) ;
1384+
1385+ if let Err ( _) = page_table. map_page ( page, frame, page_flags) {
1386+ return SyscallResult :: Err ( super :: ErrorCode :: OutOfMemory as u64 ) ;
1387+ }
1388+ flush_tlb ( VirtAddr :: new ( page_addr) ) ;
1389+ }
1390+
1391+ // Create VMA
1392+ let vma = Vma :: new (
1393+ VirtAddr :: new ( new_addr) ,
1394+ VirtAddr :: new ( new_addr + total_size) ,
1395+ Protection :: from_bits_truncate ( 3 ) ,
1396+ MmapFlags :: from_bits_truncate ( 0x21 ) , // MAP_SHARED | MAP_ANONYMOUS
1397+ ) ;
1398+ process. vmas . push ( vma) ;
1399+
1400+ crate :: serial_println!(
1401+ "[compositor] Mapped COMPOSITE_TEX into process: virt={:#x}, {}x{}, {} pages" ,
1402+ new_addr, tex_w, tex_h, num_pages
1403+ ) ;
1404+
1405+ // Write mapped address to userspace
1406+ unsafe {
1407+ core:: ptr:: write ( out_ptr as * mut u64 , new_addr) ;
1408+ }
1409+
1410+ // Return packed dimensions
1411+ SyscallResult :: Ok ( ( ( tex_w as u64 ) << 32 ) | tex_h as u64 )
1412+ }
1413+
12821414/// sys_fbdraw - Draw to the left pane of the framebuffer
12831415///
12841416/// # Arguments
0 commit comments