1#![cfg(target_os = "linux")]
7
8mod init;
9mod mapping;
10mod registrar;
11
12pub use init::BootInit;
13pub use init::Init;
14pub use init::MemoryMappings;
15pub use init::init;
16
17use aarch64defs::rsi::CcaMemPermIndex;
18use cvm_tracing::CVM_ALLOWED;
19use guestmem::GuestMemoryBackingError;
20use guestmem::PAGE_SIZE;
21use guestmem::ranges::PagedRange;
22use hcl::GuestVtl;
23use hcl::ioctl::AcceptPagesError;
24use hcl::ioctl::ApplyVtlProtectionsError;
25use hcl::ioctl::Mshv;
26use hcl::ioctl::MshvHvcall;
27use hcl::ioctl::MshvVtl;
28use hcl::ioctl::snp::SnpPageError;
29use hv1_structs::VtlArray;
30use hvdef::HV_MAP_GPA_PERMISSIONS_ALL;
31use hvdef::HV_MAP_GPA_PERMISSIONS_NONE;
32use hvdef::HV_PAGE_SHIFT;
33use hvdef::HV_PAGE_SIZE;
34use hvdef::HvError;
35use hvdef::HvMapGpaFlags;
36use hvdef::HypercallCode;
37use hvdef::hypercall::AcceptMemoryType;
38use hvdef::hypercall::HostVisibilityType;
39use hvdef::hypercall::HvInputVtl;
40use mapping::GuestMemoryMapping;
41use mapping::GuestValidMemory;
42use memory_range::MemoryRange;
43use parking_lot::Mutex;
44use parking_lot::MutexGuard;
45use registrar::RegisterMemory;
46use std::collections::VecDeque;
47use std::sync::Arc;
48use std::sync::atomic::AtomicBool;
49use thiserror::Error;
50use virt::IsolationType;
51use virt_mshv_vtl::GpnSource;
52use virt_mshv_vtl::ProtectIsolatedMemory;
53use virt_mshv_vtl::TlbFlushLockAccess;
54use vm_topology::memory::MemoryLayout;
55use x86defs::snp::SevRmpAdjust;
56use x86defs::tdx::GpaVmAttributes;
57use x86defs::tdx::GpaVmAttributesMask;
58use x86defs::tdx::TdgMemPageAttrWriteR8;
59use x86defs::tdx::TdgMemPageGpaAttr;
60
61#[derive(Debug, Error)]
63pub enum QueryVtlPermissionsError {
64 #[error("failed to query rmp permissions")]
66 Snp(#[source] SnpPageError),
67}
68
69#[derive(Debug)]
70struct MshvVtlWithPolicy {
71 mshv_vtl: MshvVtl,
72 ignore_registration_failure: bool,
73 shared: bool,
74}
75
76impl RegisterMemory for MshvVtlWithPolicy {
77 fn register_range(&self, range: MemoryRange) -> Result<(), impl 'static + std::error::Error> {
78 match self.mshv_vtl.add_vtl0_memory(range, self.shared) {
79 Ok(()) => Ok(()),
80 Err(err) if self.ignore_registration_failure => {
82 tracing::warn!(
83 CVM_ALLOWED,
84 error = &err as &dyn std::error::Error,
85 "registration failure, could be expected"
86 );
87 Ok(())
88 }
89 Err(err) => Err(err),
90 }
91 }
92}
93
94#[derive(Debug, Error)]
95#[error("failed to register memory with kernel")]
96struct RegistrationError;
97
98struct DefaultVtlPermissions {
106 vtl0: HvMapGpaFlags,
107 vtl1: Option<HvMapGpaFlags>,
108}
109
110impl DefaultVtlPermissions {
111 fn set(&mut self, vtl: GuestVtl, permissions: HvMapGpaFlags) {
112 match vtl {
113 GuestVtl::Vtl0 => self.vtl0 = permissions,
114 GuestVtl::Vtl1 => self.vtl1 = Some(permissions),
115 }
116 }
117}
118
119#[derive(Copy, Clone)]
121enum GpaVtlPermissions {
122 Vbs(HvMapGpaFlags),
123 Snp(SevRmpAdjust),
124 Tdx(TdgMemPageGpaAttr, TdgMemPageAttrWriteR8),
125 Cca(CcaMemPermIndex),
128}
129
130impl GpaVtlPermissions {
131 fn new(isolation: IsolationType, vtl: GuestVtl, protections: HvMapGpaFlags) -> Self {
132 match isolation {
133 IsolationType::None => unreachable!(),
134 IsolationType::Vbs => GpaVtlPermissions::Vbs(protections),
135 IsolationType::Snp => {
136 let mut vtl_permissions = GpaVtlPermissions::Snp(SevRmpAdjust::new());
137 vtl_permissions.set(vtl, protections);
138 vtl_permissions
139 }
140 IsolationType::Tdx => {
141 let mut vtl_permissions =
142 GpaVtlPermissions::Tdx(TdgMemPageGpaAttr::new(), TdgMemPageAttrWriteR8::new());
143 vtl_permissions.set(vtl, protections);
144 vtl_permissions
145 }
146 IsolationType::Cca => {
147 let mut vtl_permissions = GpaVtlPermissions::Cca(CcaMemPermIndex::default());
148 vtl_permissions.set(vtl, protections);
149 vtl_permissions
150 }
151 }
152 }
153
154 fn set(&mut self, vtl: GuestVtl, protections: HvMapGpaFlags) {
155 match self {
156 GpaVtlPermissions::Vbs(flags) => *flags = protections,
157 GpaVtlPermissions::Snp(rmpadjust) => {
158 *rmpadjust = SevRmpAdjust::new()
159 .with_enable_read(protections.readable())
160 .with_enable_write(protections.writable())
161 .with_enable_user_execute(protections.user_executable())
162 .with_enable_kernel_execute(protections.kernel_executable())
163 .with_target_vmpl(match vtl {
164 GuestVtl::Vtl0 => x86defs::snp::Vmpl::Vmpl2.into(),
165 GuestVtl::Vtl1 => x86defs::snp::Vmpl::Vmpl1.into(),
166 });
167 }
168 GpaVtlPermissions::Tdx(attributes, mask) => {
169 let vm_attributes = GpaVmAttributes::new()
170 .with_valid(true)
171 .with_read(protections.readable())
172 .with_write(protections.writable())
173 .with_kernel_execute(protections.kernel_executable())
174 .with_user_execute(protections.user_executable());
175
176 let (new_attributes, new_mask) = match vtl {
177 GuestVtl::Vtl0 => {
178 let attributes = TdgMemPageGpaAttr::new().with_l2_vm1(vm_attributes);
179 let mask = TdgMemPageAttrWriteR8::new()
180 .with_l2_vm1(GpaVmAttributesMask::ALL_CHANGED);
181 (attributes, mask)
182 }
183 GuestVtl::Vtl1 => {
184 let attributes = TdgMemPageGpaAttr::new().with_l2_vm2(vm_attributes);
185 let mask = TdgMemPageAttrWriteR8::new()
186 .with_l2_vm2(GpaVmAttributesMask::ALL_CHANGED);
187 (attributes, mask)
188 }
189 };
190
191 *attributes = new_attributes;
192 *mask = new_mask;
193 }
194 GpaVtlPermissions::Cca(_index) => {
195 tracing::debug!("cca: GpaVtlPermissions::set is doing nothing now");
196 }
197 }
198 }
199}
200
201#[derive(Debug, Error)]
203#[error("failed to modify gpa visibility, elements successfully processed {processed}")]
204pub struct ModifyGpaVisibilityError {
205 source: HvError,
206 processed: usize,
207}
208
209#[derive(Default)]
210struct MemoryAcceptorFlags {
211 tdx_page_release_required: bool,
212}
213
214pub struct MemoryAcceptor {
220 mshv_hvcall: MshvHvcall,
221 mshv_vtl: MshvVtl,
222 isolation: IsolationType,
223 flags: MemoryAcceptorFlags,
224}
225
226impl MemoryAcceptor {
227 pub fn new(isolation: IsolationType) -> Result<Self, hcl::ioctl::Error> {
229 let mshv = Mshv::new()?;
230 let mshv_vtl = mshv.create_vtl()?;
231 let mshv_hvcall = MshvHvcall::new()?;
232 mshv_hvcall.set_allowed_hypercalls(&[
233 HypercallCode::HvCallAcceptGpaPages,
234 HypercallCode::HvCallModifySparseGpaPageHostVisibility,
235 HypercallCode::HvCallModifyVtlProtectionMask,
236 ]);
237
238 let mut flags = MemoryAcceptorFlags::default();
239
240 if isolation == IsolationType::Tdx {
241 let config_flags = mshv_vtl.tdx_get_config_flags();
244 if config_flags.tdx_connect() {
245 assert!(
246 config_flags.page_release(),
247 "TDX Connect enabled but CONFIG_FLAGS.page_release is not set",
248 );
249
250 flags.tdx_page_release_required = true;
251 }
252 }
253
254 Ok(Self {
256 mshv_hvcall,
257 mshv_vtl,
258 isolation,
259 flags,
260 })
261 }
262
263 pub fn accept_lower_vtl_pages(&self, range: MemoryRange) -> Result<(), AcceptPagesError> {
265 match self.isolation {
266 IsolationType::None => unreachable!(),
267 IsolationType::Vbs => self
268 .mshv_hvcall
269 .accept_gpa_pages(range, AcceptMemoryType::RAM),
270 IsolationType::Snp => {
271 self.mshv_vtl
272 .pvalidate_pages(range, true, false)
273 .map_err(|err| AcceptPagesError::Snp {
274 failed_operation: err,
275 range,
276 })
277 }
278 IsolationType::Tdx => {
279 let attributes = TdgMemPageGpaAttr::new().with_l2_vm1(GpaVmAttributes::FULL_ACCESS);
280 let mask =
281 TdgMemPageAttrWriteR8::new().with_l2_vm1(GpaVmAttributesMask::ALL_CHANGED);
282
283 self.mshv_vtl
284 .tdx_accept_pages(range, Some((attributes, mask)))
285 .map_err(|err| AcceptPagesError::Tdx { error: err, range })
286 }
287 IsolationType::Cca => {
288 Ok(())
290 }
291 }
292 }
293
294 fn unaccept_lower_vtl_pages(&self, range: MemoryRange) {
295 match self.isolation {
296 IsolationType::None => unreachable!(),
297 IsolationType::Vbs => {
298 }
300 IsolationType::Snp => {
301 for lower_vtl in [GuestVtl::Vtl0, GuestVtl::Vtl1] {
308 self.apply_protections(range, lower_vtl, HV_MAP_GPA_PERMISSIONS_NONE)
309 .unwrap();
310 }
311 self.mshv_vtl.pvalidate_pages(range, false, false).unwrap()
312 }
313
314 IsolationType::Tdx => {
315 if self.flags.tdx_page_release_required {
316 self.mshv_vtl
317 .tdx_release_pages(range)
318 .unwrap_or_else(|e| panic!("Failed to release memory range {range}: {e}"));
319 }
320 }
321 IsolationType::Cca => {
322 }
324 }
325 }
326
327 pub fn modify_gpa_visibility(
329 &self,
330 host_visibility: HostVisibilityType,
331 gpns: &[u64],
332 ) -> Result<(), ModifyGpaVisibilityError> {
333 self.mshv_hvcall
334 .modify_gpa_visibility(host_visibility, gpns)
335 .map_err(|(e, processed)| ModifyGpaVisibilityError {
336 source: e,
337 processed,
338 })
339 }
340
341 pub fn apply_initial_lower_vtl_protections(
345 &self,
346 range: MemoryRange,
347 ) -> Result<(), ApplyVtlProtectionsError> {
348 self.apply_protections(range, GuestVtl::Vtl0, HV_MAP_GPA_PERMISSIONS_ALL)
349 }
350
351 fn apply_protections(
352 &self,
353 range: MemoryRange,
354 vtl: GuestVtl,
355 flags: HvMapGpaFlags,
356 ) -> Result<(), ApplyVtlProtectionsError> {
357 let permissions = GpaVtlPermissions::new(self.isolation, vtl, flags);
358
359 match permissions {
360 GpaVtlPermissions::Vbs(flags) => {
361 assert_ne!(vtl, GuestVtl::Vtl0);
364
365 self.mshv_hvcall
366 .modify_vtl_protection_mask(range, flags, HvInputVtl::from(vtl))
367 }
368 GpaVtlPermissions::Snp(rmpadjust) => {
369 self.mshv_vtl
372 .rmpadjust_pages(range, rmpadjust, false)
373 .map_err(|err| ApplyVtlProtectionsError::Snp {
374 failed_operation: err,
375 range,
376 permissions: rmpadjust,
377 vtl: vtl.into(),
378 })
379 }
380 GpaVtlPermissions::Tdx(attributes, mask) => {
381 self.mshv_vtl
384 .tdx_set_page_attributes(range, attributes, mask)
385 .map_err(|err| ApplyVtlProtectionsError::Tdx {
386 error: err,
387 range,
388 permissions: attributes,
389 vtl: vtl.into(),
390 })
391 }
392 GpaVtlPermissions::Cca(_index) => {
393 self.mshv_vtl.rsi_set_mem_perm(vtl, &range).map_err(|_err| {
394 ApplyVtlProtectionsError::Cca {
395 range,
396 vtl: vtl.into(),
397 }
398 })
399 }
400 }
401 }
402}
403
404pub struct HardwareIsolatedMemoryProtector {
406 inner: Mutex<HardwareIsolatedMemoryProtectorInner>,
408 layout: MemoryLayout,
409 acceptor: Arc<MemoryAcceptor>,
410 vtl0: Arc<GuestMemoryMapping>,
411 vtl1_protections_enabled: AtomicBool,
412}
413
414struct HardwareIsolatedMemoryProtectorInner {
415 valid_encrypted: Arc<GuestValidMemory>,
416 valid_shared: Arc<GuestValidMemory>,
417 encrypted: Arc<GuestMemoryMapping>,
418 default_vtl_permissions: DefaultVtlPermissions,
419 overlay_pages: VtlArray<Vec<OverlayPage>, 2>,
420 locked_pages: VtlArray<Vec<Box<[u64]>>, 2>,
421}
422
423struct OverlayPage {
424 gpn: u64,
425 previous_permissions: HvMapGpaFlags,
426 overlay_permissions: HvMapGpaFlags,
427 ref_count: u16,
428 gpn_source: GpnSource,
429}
430
431impl HardwareIsolatedMemoryProtector {
432 pub fn new(
437 valid_encrypted: Arc<GuestValidMemory>,
438 valid_shared: Arc<GuestValidMemory>,
439 encrypted: Arc<GuestMemoryMapping>,
440 vtl0: Arc<GuestMemoryMapping>,
441 layout: MemoryLayout,
442 acceptor: Arc<MemoryAcceptor>,
443 ) -> Self {
444 Self {
445 inner: Mutex::new(HardwareIsolatedMemoryProtectorInner {
446 valid_encrypted,
447 valid_shared,
448 encrypted,
449 default_vtl_permissions: DefaultVtlPermissions {
452 vtl0: HV_MAP_GPA_PERMISSIONS_ALL,
453 vtl1: None,
454 },
455 overlay_pages: VtlArray::from_fn(|_| Vec::new()),
456 locked_pages: VtlArray::from_fn(|_| Vec::new()),
457 }),
458 layout,
459 acceptor,
460 vtl0,
461 vtl1_protections_enabled: AtomicBool::new(false),
462 }
463 }
464
465 fn apply_protections_with_overlay_handling(
466 &self,
467 range: MemoryRange,
468 target_vtl: GuestVtl,
469 protections: HvMapGpaFlags,
470 inner: &mut MutexGuard<'_, HardwareIsolatedMemoryProtectorInner>,
471 ) -> Result<(), ApplyVtlProtectionsError> {
472 let mut range_queue = VecDeque::new();
473 range_queue.push_back(range);
474
475 'outer: while let Some(range) = range_queue.pop_front() {
476 for overlay_page in inner.overlay_pages[target_vtl].iter_mut() {
477 let overlay_addr = overlay_page.gpn * HV_PAGE_SIZE;
478 if range.contains_addr(overlay_addr) {
479 overlay_page.previous_permissions = protections;
482 let (left, right_with_overlay) =
484 range.split_at_offset(range.offset_of(overlay_addr).unwrap());
485 let (overlay, right) = right_with_overlay.split_at_offset(HV_PAGE_SIZE);
486 debug_assert_eq!(overlay.start_4k_gpn(), overlay_page.gpn);
487 debug_assert_eq!(overlay.len(), HV_PAGE_SIZE);
488 if !left.is_empty() {
489 range_queue.push_back(left);
490 }
491 if !right.is_empty() {
492 range_queue.push_back(right);
493 }
494 continue 'outer;
495 }
496 }
497 self.apply_protections(range, target_vtl, protections, GpnSource::GuestMemory)?
500 }
501
502 Ok(())
503 }
504
505 fn apply_protections(
506 &self,
507 range: MemoryRange,
508 target_vtl: GuestVtl,
509 protections: HvMapGpaFlags,
510 gpn_source: GpnSource,
511 ) -> Result<(), ApplyVtlProtectionsError> {
512 if gpn_source == GpnSource::GuestMemory && target_vtl == GuestVtl::Vtl0 {
513 self.vtl0.update_permission_bitmaps(range, protections);
515 }
516 self.acceptor
517 .apply_protections(range, target_vtl, protections)
518 }
519
520 fn query_lower_vtl_permissions(
525 &self,
526 vtl: GuestVtl,
527 gpn: u64,
528 ) -> Result<HvMapGpaFlags, HvError> {
529 if !self.is_in_guest_memory(gpn) {
530 return Err(HvError::OperationDenied);
531 }
532
533 let res = match vtl {
534 GuestVtl::Vtl0 => self
535 .vtl0
536 .query_access_permission(gpn)
537 .unwrap_or(HV_MAP_GPA_PERMISSIONS_ALL),
538 GuestVtl::Vtl1 => HV_MAP_GPA_PERMISSIONS_ALL,
539 };
540
541 Ok(res)
542 }
543
544 fn check_gpn_not_locked(
545 &self,
546 inner: &MutexGuard<'_, HardwareIsolatedMemoryProtectorInner>,
547 vtl: GuestVtl,
548 gpn: u64,
549 ) -> Result<(), HvError> {
550 if inner.locked_pages[vtl].iter().flatten().any(|x| *x == gpn)
555 && !inner.overlay_pages[vtl].iter().any(|p| p.gpn == gpn)
556 {
557 return Err(HvError::OperationDenied);
558 }
559 Ok(())
560 }
561
562 fn is_in_guest_memory(&self, gpn: u64) -> bool {
564 let gpa = gpn << HV_PAGE_SHIFT;
565 self.layout.ram().iter().any(|r| r.range.contains_addr(gpa))
566 }
567}
568
569impl ProtectIsolatedMemory for HardwareIsolatedMemoryProtector {
570 fn change_host_visibility(
571 &self,
572 vtl: GuestVtl,
573 shared: bool,
574 gpns: &[u64],
575 tlb_access: &mut dyn TlbFlushLockAccess,
576 ) -> Result<(), (HvError, usize)> {
577 let inner = self.inner.lock();
578
579 for &gpn in gpns {
580 if !self.is_in_guest_memory(gpn) {
582 return Err((HvError::OperationDenied, 0));
583 }
584
585 self.check_gpn_not_locked(&inner, vtl, gpn)
587 .map_err(|x| (x, 0))?;
588
589 if shared && inner.overlay_pages[vtl].iter().any(|p| p.gpn == gpn) {
591 return Err((HvError::OperationDenied, 0));
592 }
593 }
594
595 let orig_gpns = gpns;
599 let mut failed_vtl_permission_index = None;
600 let gpns = gpns
601 .iter()
602 .copied()
603 .enumerate()
604 .take_while(|&(index, gpn)| {
605 if vtl == GuestVtl::Vtl0 && shared && self.vtl1_protections_enabled() {
606 let permissions = self
607 .vtl0
608 .query_access_permission(gpn)
609 .expect("vtl 1 protections enabled, vtl permissions should be tracked");
610 if !permissions.readable() || !permissions.writable() {
611 failed_vtl_permission_index = Some(index);
612 false
613 } else {
614 true
615 }
616 } else {
617 true
618 }
619 })
620 .filter_map(|(_, gpn)| {
621 if inner.valid_shared.check_valid(gpn) != shared {
622 Some(gpn)
623 } else {
624 None
625 }
626 })
627 .collect::<Vec<_>>();
628
629 tracing::debug!(
630 orig = orig_gpns.len(),
631 len = gpns.len(),
632 first = gpns.first(),
633 shared,
634 "change vis"
635 );
636
637 let ranges = PagedRange::new(0, gpns.len() * PagedRange::PAGE_SIZE, &gpns)
638 .unwrap()
639 .ranges()
640 .map(|r| r.map(|r| MemoryRange::new(r.start..r.end)))
641 .collect::<Result<Vec<_>, _>>()
642 .unwrap(); let clear_bitmap = if shared {
646 &inner.valid_encrypted
647 } else {
648 &inner.valid_shared
649 };
650
651 for &range in &ranges {
652 if shared && vtl == GuestVtl::Vtl0 {
653 self.vtl0
659 .update_permission_bitmaps(range, HV_MAP_GPA_PERMISSIONS_NONE);
660 }
661
662 clear_bitmap.update_valid(range, false);
663 }
664
665 guestmem::rcu().synchronize_blocking();
672
673 if let IsolationType::Snp = self.acceptor.isolation {
674 tlb_access.flush_entire();
678 }
679
680 if shared {
681 for &range in &ranges {
683 self.acceptor.unaccept_lower_vtl_pages(range);
684 }
685 }
686
687 let host_visibility = if shared {
689 HostVisibilityType::SHARED
690 } else {
691 HostVisibilityType::PRIVATE
692 };
693
694 let (result, ranges) = match self.acceptor.modify_gpa_visibility(host_visibility, &gpns) {
695 Ok(()) => {
696 (
699 match failed_vtl_permission_index {
700 Some(index) => Err((HvError::AccessDenied, index)),
701 None => Ok(()),
702 },
703 ranges,
704 )
705 }
706 Err(err) => {
707 if shared {
708 panic!(
712 "the hypervisor refused to transition pages to shared, we cannot safely roll back: {:?}",
713 err
714 );
715 }
716
717 let (successful_gpns, failed_gpns) = gpns.split_at(err.processed);
720 let ranges = PagedRange::new(
721 0,
722 successful_gpns.len() * PagedRange::PAGE_SIZE,
723 successful_gpns,
724 )
725 .unwrap()
726 .ranges()
727 .map(|r| r.map(|r| MemoryRange::new(r.start..r.end)))
728 .collect::<Result<Vec<_>, _>>()
729 .expect("previous gpns was already checked");
730
731 let rollback_ranges =
734 PagedRange::new(0, failed_gpns.len() * PagedRange::PAGE_SIZE, failed_gpns)
735 .unwrap()
736 .ranges()
737 .map(|r| r.map(|r| MemoryRange::new(r.start..r.end)))
738 .collect::<Result<Vec<_>, _>>()
739 .expect("previous gpns was already checked");
740
741 for &range in &rollback_ranges {
742 clear_bitmap.update_valid(range, true);
743 }
744
745 let failed_index = orig_gpns
748 .iter()
749 .position(|gpn| *gpn == failed_gpns[0])
750 .expect("failed gpn should be present in the list");
751
752 (Err((err.source, failed_index)), ranges)
753 }
754 };
755
756 if !shared {
757 for &range in &ranges {
759 self.acceptor
760 .accept_lower_vtl_pages(range)
761 .expect("everything should be in a state where we can accept VTL0 pages");
762
763 if self.acceptor.isolation == IsolationType::Snp {
767 inner.encrypted.zero_range(range).expect("VTL 2 should have access to lower VTL memory, the page should be accepted, there should be no vtl protections yet.")
768 }
769 }
770 }
771
772 let set_bitmap = if shared {
774 &inner.valid_shared
775 } else {
776 &inner.valid_encrypted
777 };
778 for &range in &ranges {
779 set_bitmap.update_valid(range, true);
780 }
781
782 if !shared {
783 for &range in &ranges {
787 self.apply_protections(
789 range,
790 GuestVtl::Vtl0,
791 inner.default_vtl_permissions.vtl0,
792 GpnSource::GuestMemory,
793 )
794 .expect("should be able to apply default protections");
795
796 if let Some(vtl1_protections) = inner.default_vtl_permissions.vtl1 {
797 self.apply_protections(
798 range,
799 GuestVtl::Vtl1,
800 vtl1_protections,
801 GpnSource::GuestMemory,
802 )
803 .expect("everything should be in a state where we can apply VTL protections");
804 }
805 }
806 }
807
808 result
811 }
812
813 fn query_host_visibility(
814 &self,
815 gpns: &[u64],
816 host_visibility: &mut [HostVisibilityType],
817 ) -> Result<(), (HvError, usize)> {
818 for (i, &gpn) in gpns.iter().enumerate() {
820 if !self.is_in_guest_memory(gpn) {
821 return Err((HvError::OperationDenied, i));
822 }
823 }
824
825 let inner = self.inner.lock();
826
827 for (gpn, host_vis) in gpns.iter().zip(host_visibility.iter_mut()) {
829 *host_vis = if inner.valid_shared.check_valid(*gpn) {
830 HostVisibilityType::SHARED
831 } else {
832 HostVisibilityType::PRIVATE
833 };
834 }
835 Ok(())
836 }
837
838 fn default_vtl0_protections(&self) -> HvMapGpaFlags {
839 self.inner.lock().default_vtl_permissions.vtl0
840 }
841
842 fn change_default_vtl_protections(
843 &self,
844 target_vtl: GuestVtl,
845 vtl_protections: HvMapGpaFlags,
846 tlb_access: &mut dyn TlbFlushLockAccess,
847 ) -> Result<(), HvError> {
848 let mut inner = self.inner.lock();
855
856 inner
857 .default_vtl_permissions
858 .set(target_vtl, vtl_protections);
859
860 let mut ranges = Vec::new();
861 for ram_range in self.layout.ram().iter() {
862 let mut protect_start = ram_range.range.start();
863 let mut page_count = 0;
864
865 for gpn in
866 ram_range.range.start() / PAGE_SIZE as u64..ram_range.range.end() / PAGE_SIZE as u64
867 {
868 if inner.valid_encrypted.check_valid(gpn) {
874 self.check_gpn_not_locked(&inner, target_vtl, gpn)?;
875 page_count += 1;
876 } else {
877 if page_count > 0 {
878 let end_address = protect_start + (page_count * PAGE_SIZE as u64);
879 ranges.push(MemoryRange::new(protect_start..end_address));
880 }
881 protect_start = (gpn + 1) * PAGE_SIZE as u64;
882 page_count = 0;
883 }
884 }
885
886 if page_count > 0 {
887 let end_address = protect_start + (page_count * PAGE_SIZE as u64);
888 ranges.push(MemoryRange::new(protect_start..end_address));
889 }
890 }
891
892 for range in ranges {
893 self.apply_protections_with_overlay_handling(
894 range,
895 target_vtl,
896 vtl_protections,
897 &mut inner,
898 )
899 .unwrap();
900 }
901
902 guestmem::rcu().synchronize_blocking();
905
906 tlb_access.flush(GuestVtl::Vtl0);
909 tlb_access.set_wait_for_tlb_locks(target_vtl);
910
911 Ok(())
912 }
913
914 fn change_vtl_protections(
915 &self,
916 target_vtl: GuestVtl,
917 gpns: &[u64],
918 protections: HvMapGpaFlags,
919 tlb_access: &mut dyn TlbFlushLockAccess,
920 ) -> Result<(), (HvError, usize)> {
921 let inner = self.inner.lock();
926
927 for &gpn in gpns {
929 if !self.is_in_guest_memory(gpn) {
930 return Err((HvError::OperationDenied, 0));
931 }
932
933 self.check_gpn_not_locked(&inner, target_vtl, gpn)
935 .map_err(|x| (x, 0))?;
936
937 if inner.overlay_pages[target_vtl].iter().any(|p| p.gpn == gpn) {
939 return Err((HvError::OperationDenied, 0));
940 }
941 }
942
943 if gpns.iter().any(|&gpn| inner.valid_shared.check_valid(gpn)) {
945 return Err((HvError::OperationDenied, 0));
946 }
947
948 let ranges = PagedRange::new(0, gpns.len() * PagedRange::PAGE_SIZE, gpns)
949 .unwrap()
950 .ranges()
951 .map(|r| r.map(|r| MemoryRange::new(r.start..r.end)))
952 .collect::<Result<Vec<_>, _>>()
953 .unwrap(); for range in ranges {
956 self.apply_protections(range, target_vtl, protections, GpnSource::GuestMemory)
957 .unwrap();
958 }
959
960 guestmem::rcu().synchronize_blocking();
963
964 tlb_access.flush(GuestVtl::Vtl0);
969 tlb_access.set_wait_for_tlb_locks(target_vtl);
970
971 Ok(())
972 }
973
974 fn register_overlay_page(
975 &self,
976 vtl: GuestVtl,
977 gpn: u64,
978 gpn_source: GpnSource,
979 check_perms: HvMapGpaFlags,
980 new_perms: Option<HvMapGpaFlags>,
981 tlb_access: &mut dyn TlbFlushLockAccess,
982 ) -> Result<(), HvError> {
983 let mut inner = self.inner.lock();
984
985 if let Some(registered) = inner.overlay_pages[vtl].iter_mut().find(|p| p.gpn == gpn) {
990 let needed_perms = new_perms.unwrap_or(check_perms);
991 if registered.overlay_permissions.into_bits() | needed_perms.into_bits()
992 != registered.overlay_permissions.into_bits()
993 {
994 return Err(HvError::OperationDenied);
995 }
996 registered.ref_count += 1;
997 return Ok(());
998 }
999
1000 let current_perms = match gpn_source {
1001 GpnSource::GuestMemory => {
1002 let current_perms = self.query_lower_vtl_permissions(vtl, gpn)?;
1004 if current_perms.into_bits() | check_perms.into_bits() != current_perms.into_bits()
1005 {
1006 return Err(HvError::OperationDenied);
1007 }
1008
1009 if inner.valid_shared.check_valid(gpn) {
1011 return Err(HvError::OperationDenied);
1012 }
1013
1014 current_perms
1015 }
1016 GpnSource::Dma => {
1017 if self.is_in_guest_memory(gpn) {
1018 return Err(HvError::OperationDenied);
1020 }
1021
1022 HV_MAP_GPA_PERMISSIONS_NONE
1023 }
1024 };
1025
1026 self.check_gpn_not_locked(&inner, vtl, gpn)?;
1028
1029 if let Some(new_perms) = new_perms {
1031 self.apply_protections(
1032 MemoryRange::from_4k_gpn_range(gpn..gpn + 1),
1033 vtl,
1034 new_perms,
1035 gpn_source,
1036 )
1037 .map_err(|_| HvError::OperationDenied)?;
1038 }
1039
1040 inner.overlay_pages[vtl].push(OverlayPage {
1042 gpn,
1043 previous_permissions: current_perms,
1044 overlay_permissions: new_perms.unwrap_or(current_perms),
1045 ref_count: 1,
1046 gpn_source,
1047 });
1048
1049 guestmem::rcu().synchronize_blocking();
1052
1053 tlb_access.flush(vtl);
1058 tlb_access.set_wait_for_tlb_locks(vtl);
1059
1060 Ok(())
1061 }
1062
1063 fn unregister_overlay_page(
1064 &self,
1065 vtl: GuestVtl,
1066 gpn: u64,
1067 tlb_access: &mut dyn TlbFlushLockAccess,
1068 ) -> Result<(), HvError> {
1069 let mut inner = self.inner.lock();
1070 let overlay_pages = &mut inner.overlay_pages[vtl];
1071
1072 let index = overlay_pages
1074 .iter()
1075 .position(|p| p.gpn == gpn)
1076 .ok_or(HvError::OperationDenied)?;
1077
1078 if overlay_pages[index].ref_count > 1 {
1083 overlay_pages[index].ref_count -= 1;
1084 return Ok(());
1085 }
1086
1087 self.apply_protections(
1089 MemoryRange::from_4k_gpn_range(gpn..gpn + 1),
1090 vtl,
1091 overlay_pages[index].previous_permissions,
1092 overlay_pages[index].gpn_source,
1093 )
1094 .map_err(|_| HvError::OperationDenied)?;
1095
1096 overlay_pages.remove(index);
1098
1099 guestmem::rcu().synchronize_blocking();
1102
1103 tlb_access.flush(vtl);
1108 tlb_access.set_wait_for_tlb_locks(vtl);
1109 Ok(())
1110 }
1111
1112 fn is_overlay_page(&self, vtl: GuestVtl, gpn: u64) -> bool {
1113 self.inner.lock().overlay_pages[vtl]
1114 .iter()
1115 .any(|p| p.gpn == gpn)
1116 }
1117
1118 fn lock_gpns(&self, vtl: GuestVtl, gpns: &[u64]) -> Result<(), GuestMemoryBackingError> {
1119 self.inner.lock().locked_pages[vtl].push(gpns.to_vec().into_boxed_slice());
1126 Ok(())
1127 }
1128
1129 fn unlock_gpns(&self, vtl: GuestVtl, gpns: &[u64]) {
1130 let mut inner = self.inner.lock();
1131 let locked_pages = &mut inner.locked_pages[vtl];
1132 for (i, w) in locked_pages.iter().enumerate() {
1133 if **w == *gpns {
1134 locked_pages.swap_remove(i);
1135 return;
1136 }
1137 }
1138
1139 panic!("Tried to unlock pages that were not locked");
1145 }
1146
1147 fn set_vtl1_protections_enabled(&self) {
1148 self.vtl1_protections_enabled
1149 .store(true, std::sync::atomic::Ordering::Relaxed);
1150 }
1151
1152 fn vtl1_protections_enabled(&self) -> bool {
1153 self.vtl1_protections_enabled
1154 .load(std::sync::atomic::Ordering::Relaxed)
1155 }
1156}