diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 98cbd6447e3e..e63a2f244d7b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -681,6 +681,8 @@ struct kvm_vcpu_arch {
 	struct kvm_mmu_memory_cache mmu_gfn_array_cache;
 	struct kvm_mmu_memory_cache mmu_page_header_cache;
 
+	struct asi_pgtbl_pool asi_pgtbl_pool;
+
 	/*
 	 * QEMU userspace and the guest each have their own FPU state.
 	 * In vcpu_run, we switch between the user and guest FPU contexts.
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 9ae6168d381e..60b84331007d 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -49,6 +49,12 @@
 
 #define KVM_MMU_CR0_ROLE_BITS (X86_CR0_PG | X86_CR0_WP)
 
+#ifdef CONFIG_ADDRESS_SPACE_ISOLATION
+extern bool treat_all_userspace_as_nonsensitive;
+#else
+#define treat_all_userspace_as_nonsensitive true
+#endif
+
 static __always_inline u64 rsvd_bits(int s, int e)
 {
 	BUILD_BUG_ON(__builtin_constant_p(e) && __builtin_constant_p(s) && e < s);
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index fcdf3f8bb59a..485c0ba3ce8b 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -91,6 +91,11 @@ __MODULE_PARM_TYPE(nx_huge_pages_recovery_period_ms, "uint");
 static bool __read_mostly force_flush_and_sync_on_reuse;
 module_param_named(flush_on_reuse, force_flush_and_sync_on_reuse, bool, 0644);
 
+#ifdef CONFIG_ADDRESS_SPACE_ISOLATION
+bool __ro_after_init treat_all_userspace_as_nonsensitive;
+module_param(treat_all_userspace_as_nonsensitive, bool, 0444);
+#endif
+
 /*
  * When setting this variable to true it enables Two-Dimensional-Paging
  * where the hardware walks 2 page tables:
@@ -2757,6 +2762,21 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot,
 	return ret;
 }
 
+static void asi_map_gfn_range(struct kvm_vcpu *vcpu,
+			      struct kvm_memory_slot *slot,
+			      gfn_t gfn, size_t npages)
+{
+	int err;
+	size_t hva = __gfn_to_hva_memslot(slot, gfn);
+
+	err = asi_map_user(vcpu->kvm->asi, (void *)hva, PAGE_SIZE * npages,
+			   &vcpu->arch.asi_pgtbl_pool, slot->userspace_addr,
+			   slot->userspace_addr + slot->npages * PAGE_SIZE);
+	if (err)
+		kvm_err("asi_map_user for %lx-%lx failed with code %d", hva,
+			hva + PAGE_SIZE * npages, err);
+}
+
 static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
 				    struct kvm_mmu_page *sp,
 				    u64 *start, u64 *end)
@@ -2776,6 +2796,9 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
 	if (ret <= 0)
 		return -1;
 
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_map_gfn_range(vcpu, slot, gfn, ret);
+
 	for (i = 0; i < ret; i++, gfn++, start++) {
 		mmu_set_spte(vcpu, slot, start, access, gfn,
 			     page_to_pfn(pages[i]), NULL);
@@ -3980,6 +4003,15 @@ static bool kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
 	return true;
 }
 
+static void vcpu_fill_asi_pgtbl_pool(struct kvm_vcpu *vcpu)
+{
+	int err = asi_fill_pgtbl_pool(&vcpu->arch.asi_pgtbl_pool,
+				      CONFIG_PGTABLE_LEVELS - 1, GFP_KERNEL);
+
+	if (err)
+		kvm_err("asi_fill_pgtbl_pool failed with code %d", err);
+}
+
 /*
  * Returns true if the page fault is stale and needs to be retried, i.e. if the
  * root was invalidated by a memslot update or a relevant mmu_notifier fired.
@@ -4013,6 +4045,7 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	bool is_tdp_mmu_fault = is_tdp_mmu(vcpu->arch.mmu);
 
 	unsigned long mmu_seq;
+	bool try_asi_map;
 	int r;
 
 	fault->gfn = fault->addr >> PAGE_SHIFT;
@@ -4038,6 +4071,12 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	if (handle_abnormal_pfn(vcpu, fault, ACC_ALL, &r))
 		return r;
 
+	try_asi_map = !treat_all_userspace_as_nonsensitive &&
+		      !is_noslot_pfn(fault->pfn);
+
+	if (try_asi_map)
+		vcpu_fill_asi_pgtbl_pool(vcpu);
+
 	r = RET_PF_RETRY;
 
 	if (is_tdp_mmu_fault)
@@ -4052,6 +4091,9 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	if (r)
 		goto out_unlock;
 
+	if (try_asi_map)
+		asi_map_gfn_range(vcpu, fault->slot, fault->gfn, 1);
+
 	if (is_tdp_mmu_fault)
 		r = kvm_tdp_mmu_map(vcpu, fault);
 	else
@@ -5584,6 +5626,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
 
 	vcpu->arch.nested_mmu.translate_gpa = translate_nested_gpa;
 
+	asi_init_pgtbl_pool(&vcpu->arch.asi_pgtbl_pool);
+
 	ret = __kvm_mmu_create(vcpu, &vcpu->arch.guest_mmu);
 	if (ret)
 		return ret;
@@ -5713,6 +5757,15 @@ static void kvm_mmu_invalidate_zap_pages_in_memslot(struct kvm *kvm,
 			struct kvm_memory_slot *slot,
 			struct kvm_page_track_notifier_node *node)
 {
+	/*
+	 * Currently, we just zap the entire address range, instead of only the
+	 * memslot. So we also just asi_unmap the entire userspace. But in the
+	 * future, if we zap only the range belonging to the memslot, then we
+	 * should also asi_unmap only that range.
+	 */
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_unmap_user(kvm->asi, 0, TASK_SIZE_MAX);
+
 	kvm_mmu_zap_all_fast(kvm);
 }
 
@@ -6194,6 +6247,7 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
 	free_mmu_pages(&vcpu->arch.root_mmu);
 	free_mmu_pages(&vcpu->arch.guest_mmu);
 	mmu_free_memory_caches(vcpu);
+	asi_clear_pgtbl_pool(&vcpu->arch.asi_pgtbl_pool);
 }
 
 void kvm_mmu_module_exit(void)
diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index 708a5d297fe1..193317ad60a4 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -584,6 +584,9 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
 	if (is_error_pfn(pfn))
 		return false;
 
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_map_gfn_range(vcpu, slot, gfn, 1);
+
 	mmu_set_spte(vcpu, slot, spte, pte_access, gfn, pfn, NULL);
 	kvm_release_pfn_clean(pfn);
 	return true;
@@ -836,6 +839,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	int r;
 	unsigned long mmu_seq;
 	bool is_self_change_mapping;
+	bool try_asi_map;
 
 	pgprintk("%s: addr %lx err %x\n", __func__, fault->addr, fault->error_code);
 	WARN_ON_ONCE(fault->is_tdp);
@@ -890,6 +894,12 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	if (handle_abnormal_pfn(vcpu, fault, walker.pte_access, &r))
 		return r;
 
+	try_asi_map = !treat_all_userspace_as_nonsensitive &&
+		      !is_noslot_pfn(fault->pfn);
+
+	if (try_asi_map)
+		vcpu_fill_asi_pgtbl_pool(vcpu);
+
 	/*
 	 * Do not change pte_access if the pfn is a mmio page, otherwise
 	 * we will cache the incorrect access into mmio spte.
@@ -919,6 +929,10 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
 	r = make_mmu_pages_available(vcpu);
 	if (r)
 		goto out_unlock;
+
+	if (try_asi_map)
+		asi_map_gfn_range(vcpu, fault->slot, walker.gfn, 1);
+
 	r = FNAME(fetch)(vcpu, fault, &walker);
 	kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index dd07f677d084..d0df14deae80 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8722,7 +8722,10 @@ int kvm_arch_init(void *opaque)
 		goto out_free_percpu;
 
 	if (ops->runtime_ops->flush_sensitive_cpu_state) {
-		r = asi_register_class("KVM", ASI_MAP_STANDARD_NONSENSITIVE,
+		r = asi_register_class("KVM",
+				       ASI_MAP_STANDARD_NONSENSITIVE |
+				       (treat_all_userspace_as_nonsensitive ?
+					ASI_MAP_ALL_USERSPACE : 0),
 				       &kvm_asi_hooks);
 		if (r < 0)
 			goto out_mmu_exit;
@@ -9675,6 +9678,17 @@ void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
 	apic_address = gfn_to_hva(kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT);
 	if (start <= apic_address && apic_address < end)
 		kvm_make_all_cpus_request(kvm, KVM_REQ_APIC_PAGE_RELOAD);
+
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_unmap_user(kvm->asi, (void *)start, end - start);
+}
+
+void kvm_arch_mmu_notifier_invalidate_range_start(struct kvm *kvm,
+						  unsigned long start,
+						  unsigned long end)
+{
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_unmap_user(kvm->asi, (void *)start, end - start);
 }
 
 void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
@@ -11874,6 +11888,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 
 void kvm_arch_flush_shadow_all(struct kvm *kvm)
 {
+	if (!treat_all_userspace_as_nonsensitive)
+		asi_unmap_user(kvm->asi, 0, TASK_SIZE_MAX);
+
 	kvm_mmu_zap_all(kvm);
 }
 
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 9dd63ed21f75..f31f7442eced 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1819,6 +1819,9 @@ static inline long kvm_arch_vcpu_async_ioctl(struct file *filp,
 
 void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
 					    unsigned long start, unsigned long end);
+void kvm_arch_mmu_notifier_invalidate_range_start(struct kvm *kvm,
+						  unsigned long start,
+						  unsigned long end);
 
 #ifdef CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE
 int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 72c4e6b39389..e8e9c8588908 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -162,6 +162,12 @@ __weak void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
 {
 }
 
+__weak void kvm_arch_mmu_notifier_invalidate_range_start(struct kvm *kvm,
+							 unsigned long start,
+							 unsigned long end)
+{
+}
+
 bool kvm_is_zone_device_pfn(kvm_pfn_t pfn)
 {
 	/*
@@ -685,6 +691,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
 	spin_unlock(&kvm->mn_invalidate_lock);
 
 	__kvm_handle_hva_range(kvm, &hva_range);
+	kvm_arch_mmu_notifier_invalidate_range_start(kvm, range->start, range->end);
 
 	return 0;
 }
