Skip to content

Commit a3d8e19

Browse files
konstantin-s-bogomgvisor-bot
authored andcommitted
KVM: Dynamically size IPA and fault blocks on ARM64
KVM on ARM64 defaults to 40-bit IPA, but can be dynamically limited by the host. Previously, we assumed a fixed 40-bit IPA and used large fault block sizes (up to 4TB), which could lead to GPAs exceeding the guest's IPA space. This caused sentry to crash with "set memory region failed" (EFAULT/EINVAL) during platform initialization. Fix this by: 1. Dynamically detecting host max IPA and limiting PhysicalAddressBits (up to 40). 2. Reducing faultBlockSize to 1GB (from 8GB) on ARM64 if IPA is <= 39-bit to pack GPAs tighter. PiperOrigin-RevId: 938863212
1 parent a29997e commit a3d8e19

6 files changed

Lines changed: 51 additions & 8 deletions

File tree

pkg/ring0/aarch64.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,16 @@ package ring0
1919
const (
2020
// VirtualAddressBits is fixed at 48.
2121
VirtualAddressBits = 48
22+
)
2223

23-
// PhysicalAddressBits is fixed at 40.
24-
PhysicalAddressBits = 40
24+
var (
25+
// PhysicalAddressBits is the number of bits available in the physical
26+
// address space. On ARM64, this is dynamically limited by the host KVM IPA size,
27+
// up to a maximum of 40 bits.
28+
PhysicalAddressBits uintptr = 40
29+
)
2530

31+
const (
2632
// DAIF bits:debug, sError, IRQ, FIQ.
2733
_PSR_D_BIT = 0x00000200
2834
_PSR_A_BIT = 0x00000100

pkg/sentry/platform/kvm/kvm_amd64.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ func updateGlobalOnce(fd int) error {
248248
ring0.Init(cpuid.FeatureSet{
249249
Function: s,
250250
})
251+
initFaultBlocks()
251252
physicalInit()
252253
return nil
253254
}

pkg/sentry/platform/kvm/kvm_arm64.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ package kvm
2020
import (
2121
"fmt"
2222

23+
"golang.org/x/sys/unix"
2324
"gvisor.dev/gvisor/pkg/abi/linux"
25+
"gvisor.dev/gvisor/pkg/hostsyscall"
2426
"gvisor.dev/gvisor/pkg/ring0"
2527
"gvisor.dev/gvisor/pkg/sentry/arch"
2628
)
@@ -66,7 +68,18 @@ type kvmVcpuEvents struct {
6668
// updateGlobalOnce does global initialization. It has to be called only once.
6769
func updateGlobalOnce(fd int) error {
6870
err := updateSystemValues(int(fd))
71+
72+
maxIPA, errno := hostsyscall.RawSyscall(unix.SYS_IOCTL, uintptr(fd), KVM_CHECK_EXTENSION, _KVM_CAP_ARM_VM_IPA_SIZE)
73+
if errno == 0 && maxIPA > 0 {
74+
if maxIPA < 40 {
75+
ring0.PhysicalAddressBits = uintptr(maxIPA)
76+
} else {
77+
ring0.PhysicalAddressBits = 40
78+
}
79+
}
80+
6981
ring0.Init()
82+
initFaultBlocks()
7083
physicalInit()
7184

7285
// Explicitly configure address space for 48-bit VA.

pkg/sentry/platform/kvm/machine.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,9 @@ func newMachine(vm int, config *Config) (*machine, error) {
331331
// mmap isn't called frequently, it seems better than the memory and
332332
// startup time overhead introduced by mapping the entire address
333333
// space.
334-
mapEntireAddressSpace := forceMappingEntireAddressSpace ||
335-
runtime.GOARCH != "amd64"
334+
mapEntireAddressSpace := forceMappingEntireAddressSpace || mapEntireAddressSpaceDefault
336335
if mapEntireAddressSpace {
337-
// Increase faultBlockSize to be sure that we will not reach the limit.
338-
// faultBlockSize has to equal or less than KVM_MEM_MAX_NR_PAGES.
339-
faultBlockSize = uintptr(1) << 42
340-
faultBlockMask = ^uintptr(faultBlockSize - 1)
336+
archOverrideFaultBlocks()
341337
} else {
342338
// Install seccomp rules to trap runtime mmap system calls. They will
343339
// be handled by seccompMmapHandler.

pkg/sentry/platform/kvm/machine_amd64.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,3 +579,17 @@ func (m *machine) getMaxVCPU() {
579579
func archPhysicalRegions(physicalRegions []physicalRegion) []physicalRegion {
580580
return physicalRegions
581581
}
582+
583+
const mapEntireAddressSpaceDefault = false
584+
585+
func initFaultBlocks() {
586+
faultBlockSize = uintptr(8 << 30) // 8 GiB
587+
faultBlockMask = ^uintptr(faultBlockSize - 1)
588+
}
589+
590+
func archOverrideFaultBlocks() {
591+
// Increase faultBlockSize to be sure that we will not reach the limit.
592+
// faultBlockSize has to equal or less than KVM_MEM_MAX_NR_PAGES.
593+
faultBlockSize = uintptr(1) << 42
594+
faultBlockMask = ^uintptr(faultBlockSize - 1)
595+
}

pkg/sentry/platform/kvm/machine_arm64.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,16 @@ func (m *machine) getMaxVCPU() {
205205
}
206206
}
207207
}
208+
209+
const mapEntireAddressSpaceDefault = true
210+
211+
func initFaultBlocks() {
212+
if ring0.PhysicalAddressBits <= 39 {
213+
faultBlockSize = uintptr(1 << 30) // 1 GiB
214+
} else {
215+
faultBlockSize = uintptr(8 << 30) // 8 GiB
216+
}
217+
faultBlockMask = ^uintptr(faultBlockSize - 1)
218+
}
219+
220+
func archOverrideFaultBlocks() {}

0 commit comments

Comments
 (0)