return ret;
 
        for (i = 0; i < hyp_nr_cpus; i++) {
+               struct kvm_nvhe_init_params *params = per_cpu_ptr(&kvm_init_params, i);
+               unsigned long hyp_addr;
+
                start = (void *)kern_hyp_va(per_cpu_base[i]);
                end = start + PAGE_ALIGN(hyp_percpu_size);
                ret = pkvm_create_mappings(start, end, PAGE_HYP);
                if (ret)
                        return ret;
 
-               end = (void *)per_cpu_ptr(&kvm_init_params, i)->stack_hyp_va;
-               start = end - PAGE_SIZE;
-               ret = pkvm_create_mappings(start, end, PAGE_HYP);
+               /*
+                * Allocate a contiguous HYP private VA range for the stack
+                * and guard page. The allocation is also aligned based on
+                * the order of its size.
+                */
+               ret = pkvm_alloc_private_va_range(PAGE_SIZE * 2, &hyp_addr);
+               if (ret)
+                       return ret;
+
+               /*
+                * Since the stack grows downwards, map the stack to the page
+                * at the higher address and leave the lower guard page
+                * unbacked.
+                *
+                * Any valid stack address now has the PAGE_SHIFT bit as 1
+                * and addresses corresponding to the guard page have the
+                * PAGE_SHIFT bit as 0 - this is used for overflow detection.
+                */
+               hyp_spin_lock(&pkvm_pgd_lock);
+               ret = kvm_pgtable_hyp_map(&pkvm_pgtable, hyp_addr + PAGE_SIZE,
+                                       PAGE_SIZE, params->stack_pa, PAGE_HYP);
+               hyp_spin_unlock(&pkvm_pgd_lock);
                if (ret)
                        return ret;
+
+               /* Update stack_hyp_va to end of the stack's private VA range */
+               params->stack_hyp_va = hyp_addr + (2 * PAGE_SIZE);
        }
 
        /*