kvm/arm: calculate virtual-to-physical mappings only once

This commit is contained in:
Andrei Vagin
2021-09-22 13:41:18 -07:00
committed by Andrei Vagin
parent c1a726e8c5
commit 981111a9ee
4 changed files with 146 additions and 29 deletions
+23 -23
View File
@@ -192,6 +192,10 @@ func (m *machine) newVCPU() *vCPU {
return c // Done.
}
// readOnlyGuestRegions contains regions that have to be mapped read-only into
// the guest physical address space. Right now, it is used on arm64 only.
var readOnlyGuestRegions []region
// newMachine returns a new VM context.
func newMachine(vm int) (*machine, error) {
// Create the machine.
@@ -241,32 +245,11 @@ func newMachine(vm int) (*machine, error) {
return true // Keep iterating.
})
var physicalRegionsReadOnly []physicalRegion
var physicalRegionsAvailable []physicalRegion
physicalRegionsReadOnly = rdonlyRegionsForSetMem()
physicalRegionsAvailable = availableRegionsForSetMem()
// Map all read-only regions.
for _, r := range physicalRegionsReadOnly {
m.mapPhysical(r.physical, r.length, physicalRegionsReadOnly, _KVM_MEM_READONLY)
}
// Ensure that the currently mapped virtual regions are actually
// available in the VM. Note that this doesn't guarantee no future
// faults, however it should guarantee that everything is available to
// ensure successful vCPU entry.
applyVirtualRegions(func(vr virtualRegion) {
if excludeVirtualRegion(vr) {
return // skip region.
}
for _, r := range physicalRegionsReadOnly {
if vr.virtual == r.virtual {
return
}
}
mapRegion := func(vr region, flags uint32) {
for virtual := vr.virtual; virtual < vr.virtual+vr.length; {
physical, length, ok := translateToPhysical(virtual)
if !ok {
@@ -280,9 +263,26 @@ func newMachine(vm int) (*machine, error) {
}
// Ensure the physical range is mapped.
m.mapPhysical(physical, length, physicalRegionsAvailable, _KVM_MEM_FLAGS_NONE)
m.mapPhysical(physical, length, physicalRegions, flags)
virtual += length
}
}
for _, vr := range(readOnlyGuestRegions) {
mapRegion(vr, _KVM_MEM_READONLY)
}
applyVirtualRegions(func(vr virtualRegion) {
if excludeVirtualRegion(vr) {
return // skip region.
}
for _, r := range readOnlyGuestRegions {
if vr.virtual == r.virtual {
return
}
}
mapRegion(vr.region, 0)
})
// Initialize architecture state.
+4
View File
@@ -522,3 +522,7 @@ func (m *machine) getNewVCPU() *vCPU {
}
return nil
}
func archPhysicalRegions(physicalRegions []physicalRegion) ([]physicalRegion) {
return physicalRegions
}
+116 -6
View File
@@ -110,18 +110,128 @@ func rdonlyRegionsForSetMem() (phyRegions []physicalRegion) {
return phyRegions
}
// Get all available physicalRegions.
func availableRegionsForSetMem() (phyRegions []physicalRegion) {
var excludeRegions []region
// archPhysicalRegions fills readOnlyGuestRegions and allocates separate
// physical regions form them.
func archPhysicalRegions(physicalRegions []physicalRegion) ([]physicalRegion) {
applyVirtualRegions(func(vr virtualRegion) {
if excludeVirtualRegion(vr) {
return // skip region.
}
if !vr.accessType.Write {
excludeRegions = append(excludeRegions, vr.region)
readOnlyGuestRegions = append(readOnlyGuestRegions, vr.region)
}
})
phyRegions = computePhysicalRegions(excludeRegions)
rdRegions := readOnlyGuestRegions[:]
return phyRegions
// Add an unreachable region.
rdRegions = append(rdRegions, region {
virtual: 0xffffffffffffffff,
length: 0,
})
var regions []physicalRegion
addValidRegion := func(r *physicalRegion, virtual, length uintptr) {
if length == 0 {
return
}
regions = append(regions, physicalRegion {
region: region{
virtual: virtual,
length: length,
},
physical: r.physical + (virtual - r.virtual),
})
}
i := 0
for _, pr := range(physicalRegions) {
start := pr.virtual
end := pr.virtual + pr.length
for start < end {
rdRegion := rdRegions[i]
rdStart := rdRegion.virtual
rdEnd := rdRegion.virtual + rdRegion.length
if rdEnd <= start {
i++
continue
}
if rdStart > start {
newEnd := rdStart
if end < rdStart {
newEnd = end
}
addValidRegion(&pr, start, newEnd - start)
start = rdStart
continue
}
if rdEnd < end {
addValidRegion(&pr, start, rdEnd - start)
start = rdEnd
continue
}
addValidRegion(&pr, start, end - start)
start = end
}
}
return regions
}
// Get all available physicalRegions.
func availableRegionsForSetMem() ([]physicalRegion) {
var excludedRegions []region
applyVirtualRegions(func(vr virtualRegion) {
if !vr.accessType.Write {
excludedRegions = append(excludedRegions, vr.region)
}
})
// Add an unreachable region.
excludedRegions = append(excludedRegions, region {
virtual: 0xffffffffffffffff,
length: 0,
})
var regions []physicalRegion
addValidRegion := func(r *physicalRegion, virtual, length uintptr) {
if length == 0 {
return
}
regions = append(regions, physicalRegion {
region: region{
virtual: virtual,
length: length,
},
physical: r.physical + (virtual - r.virtual),
})
}
i := 0
for _, pr := range(physicalRegions) {
start := pr.virtual
end := pr.virtual + pr.length
for start < end {
er := excludedRegions[i]
excludeEnd := er.virtual + er.length
excludeStart := er.virtual
if excludeEnd < start {
i++
continue
}
if excludeStart < start {
start = excludeEnd
i++
continue
}
rend := excludeStart
if rend > end {
rend = end
}
addValidRegion(&pr, start, rend - start)
start = excludeEnd
}
}
return regions
}
// nonCanonical generates a canonical address return.
+3
View File
@@ -168,6 +168,9 @@ func computePhysicalRegions(excludedRegions []region) (physicalRegions []physica
}
addValidRegion(lastExcludedEnd, ring0.MaximumUserAddress-lastExcludedEnd)
// Do arch-specific actions on physical regions.
physicalRegions = archPhysicalRegions(physicalRegions)
// Dump our all physical regions.
for _, r := range physicalRegions {
log.Infof("physicalRegion: virtual [%x,%x) => physical [%x,%x)",