Skip to content

Commit 26632eb

Browse files
Addressed review comments-Changed logic to use GPNs
1 parent 3e0d4a4 commit 26632eb

File tree

1 file changed

+54
-18
lines changed
  • vm/devices/storage/ide/src

1 file changed

+54
-18
lines changed

vm/devices/storage/ide/src/lib.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod drive;
88
mod protocol;
99

1010
use crate::drive::save_restore::DriveSaveRestore;
11+
use crate::PAGE_SIZE64;
1112
use crate::protocol::BusMasterReg;
1213
use crate::protocol::DeviceControlReg;
1314
use crate::protocol::IdeCommand;
@@ -27,6 +28,7 @@ use disk_backend::Disk;
2728
use drive::DiskDrive;
2829
use drive::DriveRegister;
2930
use guestmem::GuestMemory;
31+
use guestmem::ranges::PagedRange;
3032
use ide_resources::IdePath;
3133
use inspect::Inspect;
3234
use inspect::InspectMut;
@@ -49,7 +51,7 @@ use thiserror::Error;
4951
use vmcore::device_state::ChangeDeviceState;
5052
use vmcore::line_interrupt::LineInterrupt;
5153
use zerocopy::IntoBytes;
52-
//use guestmem::GuestMemoryErrorKind;
54+
use guestmem::ranges::PagedRange;
5355

5456
open_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

Comments
 (0)