@@ -8,6 +8,7 @@ mod drive;
88mod protocol;
99
1010use crate :: drive:: save_restore:: DriveSaveRestore ;
11+ use crate :: PAGE_SIZE64 ;
1112use crate :: protocol:: BusMasterReg ;
1213use crate :: protocol:: DeviceControlReg ;
1314use crate :: protocol:: IdeCommand ;
@@ -27,6 +28,7 @@ use disk_backend::Disk;
2728use drive:: DiskDrive ;
2829use drive:: DriveRegister ;
2930use guestmem:: GuestMemory ;
31+ use guestmem:: ranges:: PagedRange ;
3032use ide_resources:: IdePath ;
3133use inspect:: Inspect ;
3234use inspect:: InspectMut ;
@@ -49,7 +51,7 @@ use thiserror::Error;
4951use vmcore:: device_state:: ChangeDeviceState ;
5052use vmcore:: line_interrupt:: LineInterrupt ;
5153use zerocopy:: IntoBytes ;
52- // use guestmem::GuestMemoryErrorKind ;
54+ use guestmem:: ranges :: PagedRange ;
5355
5456open_enum ! {
5557 pub enum IdeIoPort : u16 {
@@ -697,29 +699,40 @@ impl Channel {
697699 write. deferred . complete ( ) ;
698700 }
699701
702+ fn gpa_to_gpn ( gpa : u64 ) -> u64 {
703+ gpa / PAGE_SIZE64
704+ }
705+
700706 fn perform_dma_memory_phase ( & mut self ) {
707+ tracing:: trace!( "perform_dma_memory_phase" ) ;
701708 let Some ( drive) = & mut self . drives [ self . state . current_drive_idx ] else {
709+ tracing:: trace!( "returning from perform_dma_memory_phase" ) ;
702710 return ;
703711 } ;
704712
705713 if self . bus_master_state . dma_error {
714+ tracing:: trace!( "DMA error" ) ;
706715 if drive. handle_read_dma_descriptor_error ( ) {
707716 self . bus_master_state . dma_error = false ;
708717 }
709718 return ;
710719 }
711720
721+ tracing:: trace!( dmaState = ?self . bus_master_state. dma_state, dmaType = ?self . bus_master_state. dma_io_type( ) , "DMA state" ) ;
712722 let ( dma_type, mut dma_avail) = match drive. dma_request ( ) {
713723 Some ( ( dma_type, avail) ) if * dma_type == self . bus_master_state . dma_io_type ( ) => {
714724 ( Some ( * dma_type) , avail as u32 )
715725 }
716726 _ => {
717727 // No active, appropriate DMA buffer.
728+ tracing:: trace!( "Invalid dma : returning from perform_dma_memory_phase" ) ;
718729 return ;
719730 }
720731 } ;
721- tracing:: trace!( dma_type = ?dma_type, "DMA TYPE here" ) ;
732+
733+ tracing:: trace!( dmaType = ?dma_type, dmaAvail = ?dma_avail, busMasterState = ?self . bus_master_state. dma_state, "DMA TYPE here" ) ;
722734 let Some ( dma) = & mut self . bus_master_state . dma_state else {
735+ tracing:: trace!( "No active DMA state" ) ;
723736 return ;
724737 } ;
725738
@@ -769,30 +782,39 @@ impl Channel {
769782 dma. transfer_bytes_left = 0x10000 ;
770783 }
771784
772- // Check that the base address is within the guest's physical address space.
785+ // Check that the every page starting from the base address is within
786+ // the guest's physical address space.
773787 // This is a sanity check, the guest should not be able to program the DMA
774- // controller with an invalid address.
775-
776- if let Some ( dma_type) = dma_type {
777- let end_addr = cur_desc_table_entry
778- . mem_physical_base
779- . checked_add ( dma. transfer_bytes_left ) ;
780- let r = match ( dma_type, end_addr) {
781- ( DmaType :: Read , Some ( end) ) => {
788+ // controller with an invalid page access.
789+
790+ let end_gpa = cur_desc_table_entry
791+ . mem_physical_base
792+ . checked_add ( dma. transfer_bytes_left ) ;
793+
794+ if let Some ( end_gpa) = end_gpa {
795+ let start_gpn = Self :: gpa_to_gpn ( cur_desc_table_entry. mem_physical_base . into ( ) ) ;
796+ let end_gpn = Self :: gpa_to_gpn ( end_gpa. into ( ) ) ;
797+ tracing:: trace!( startGpa = ?cur_desc_table_entry. mem_physical_base, endGpa = ?end_gpa, "start and end GPAs" ) ;
798+ tracing:: trace!( startGpn = ?start_gpn, endGpn = ?end_gpn, "start and end GPNs" ) ;
799+ let gpns: Vec < u64 > = ( start_gpn..end_gpn) . collect ( ) ;
800+
801+ tracing:: trace!( paged_range = ?PagedRange :: new( 0 , gpns. len( ) * PAGE_SIZE64 as usize , & gpns) , "PagedRange of GPNs" ) ;
802+ tracing:: trace!( gpns_vector = ?gpns, gpns_len = ?gpns. len( ) , "PagedRange values" ) ;
803+ let paged_range = PagedRange :: new ( 0 , gpns. len ( ) * PAGE_SIZE64 as usize , & gpns) . unwrap ( ) ;
804+ let r = match dma_type. unwrap ( ) {
805+ DmaType :: Read => {
782806 self . guest_memory
783- . probe_gpa_readable ( end . into ( ) )
807+ . probe_gpn_readable_range ( & paged_range )
784808 } ,
785- ( DmaType :: Write , Some ( end ) ) => {
809+ DmaType :: Write => {
786810 self . guest_memory
787- . probe_gpa_writable ( end . into ( ) )
811+ . probe_gpn_writable_range ( & paged_range )
788812 } ,
789- ( _, None ) => Err ( guestmem:: GuestMemoryErrorKind :: OutOfRange ) ,
790813 } ;
791814 if let Err ( err) = r {
792815 // If there is an error and there is no other IO in parallel,
793816 // we need to stop the current DMA transfer and set the error bit
794817 // in the Bus Master Status register.
795-
796818 self . bus_master_state . dma_state = None ;
797819 if !drive. handle_read_dma_descriptor_error ( ) {
798820 self . bus_master_state . dma_error = true ;
@@ -803,9 +825,22 @@ impl Channel {
803825 "dma base address out-of-range error"
804826 ) ;
805827 return ;
806- } ;
828+ }
829+ } else {
830+ // If there is an error and there is no other IO in parallel,
831+ // we need to stop the current DMA transfer and set the error bit
832+ // in the Bus Master Status register.
833+ self . bus_master_state . dma_state = None ;
834+ if !drive. handle_read_dma_descriptor_error ( ) {
835+ self . bus_master_state . dma_error = true ;
836+ }
837+
838+ tracelimit:: error_ratelimited!(
839+ "dma base address out-of-range error"
840+ ) ;
841+ return ;
807842 }
808-
843+
809844 dma. transfer_base_addr = cur_desc_table_entry. mem_physical_base . into ( ) ;
810845 dma. transfer_complete = ( cur_desc_table_entry. end_of_table & 0x80 ) != 0 ;
811846
@@ -821,6 +856,7 @@ impl Channel {
821856
822857 assert ! ( bytes_to_transfer != 0 ) ;
823858
859+ tracing:: trace!( bytes_to_transfer = ?bytes_to_transfer, "bytes to transfer" ) ;
824860 drive. dma_transfer (
825861 & self . guest_memory ,
826862 dma. transfer_base_addr ,
0 commit comments