summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/kvm
diff options
context:
space:
mode:
authorAdin Scannell <ascannell@google.com>2018-06-06 21:47:39 -0700
committerShentubot <shentubot@google.com>2018-06-06 21:48:24 -0700
commit1b5062263b4a3ca3dc0271d9e06ad0113197344c (patch)
tree69d6536240ffa1db76aaef0d4f3a873d86a0dfaf /pkg/sentry/platform/kvm
parent206e90d057211f2ac53174907b2ff04801f9a481 (diff)
Add allocator abstraction for page tables.
In order to prevent possible garbage collection and reuse of page table pages prior to invalidation, introduce a former allocator abstraction that can ensure entries are held during a single traversal. This also cleans up the abstraction and splits it out of the machine itself. PiperOrigin-RevId: 199581636 Change-Id: I2257d5d7ffd9c36f9b7ecd42f769261baeaf115c
Diffstat (limited to 'pkg/sentry/platform/kvm')
-rw-r--r--pkg/sentry/platform/kvm/BUILD1
-rw-r--r--pkg/sentry/platform/kvm/address_space.go5
-rw-r--r--pkg/sentry/platform/kvm/allocator.go69
-rw-r--r--pkg/sentry/platform/kvm/bluepill_fault.go4
-rw-r--r--pkg/sentry/platform/kvm/kvm.go2
-rw-r--r--pkg/sentry/platform/kvm/machine.go6
-rw-r--r--pkg/sentry/platform/kvm/machine_unsafe.go12
-rw-r--r--pkg/sentry/platform/kvm/physical_map.go14
8 files changed, 88 insertions, 25 deletions
diff --git a/pkg/sentry/platform/kvm/BUILD b/pkg/sentry/platform/kvm/BUILD
index 004938080..89d98c5c7 100644
--- a/pkg/sentry/platform/kvm/BUILD
+++ b/pkg/sentry/platform/kvm/BUILD
@@ -28,6 +28,7 @@ go_library(
srcs = [
"address_space.go",
"address_space_unsafe.go",
+ "allocator.go",
"bluepill.go",
"bluepill_amd64.go",
"bluepill_amd64.s",
diff --git a/pkg/sentry/platform/kvm/address_space.go b/pkg/sentry/platform/kvm/address_space.go
index 4c76883ad..15d45f5bc 100644
--- a/pkg/sentry/platform/kvm/address_space.go
+++ b/pkg/sentry/platform/kvm/address_space.go
@@ -84,7 +84,7 @@ func (as *addressSpace) Touch(c *vCPU) bool {
func (as *addressSpace) mapHost(addr usermem.Addr, m hostMapEntry, at usermem.AccessType) (inv bool) {
for m.length > 0 {
- physical, length, ok := TranslateToPhysical(m.addr)
+ physical, length, ok := translateToPhysical(m.addr)
if !ok {
panic("unable to translate segment")
}
@@ -227,4 +227,7 @@ func (as *addressSpace) Unmap(addr usermem.Addr, length uint64) {
func (as *addressSpace) Release() {
as.Unmap(0, ^uint64(0))
as.pageTables.Release()
+
+ // Free all pages from the allocator.
+ as.pageTables.Allocator.(allocator).base.Drain()
}
diff --git a/pkg/sentry/platform/kvm/allocator.go b/pkg/sentry/platform/kvm/allocator.go
new file mode 100644
index 000000000..80066bfc5
--- /dev/null
+++ b/pkg/sentry/platform/kvm/allocator.go
@@ -0,0 +1,69 @@
+// Copyright 2018 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package kvm
+
+import (
+ "fmt"
+
+ "gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0/pagetables"
+)
+
+type allocator struct {
+ base *pagetables.RuntimeAllocator
+}
+
+// newAllocator is used to define the allocator.
+func newAllocator() allocator {
+ return allocator{
+ base: pagetables.NewRuntimeAllocator(),
+ }
+}
+
+// NewPTEs implements pagetables.Allocator.NewPTEs.
+//
+//go:nosplit
+func (a allocator) NewPTEs() *pagetables.PTEs {
+ return a.base.NewPTEs()
+}
+
+// PhysicalFor returns the physical address for a set of PTEs.
+//
+//go:nosplit
+func (a allocator) PhysicalFor(ptes *pagetables.PTEs) uintptr {
+ virtual := a.base.PhysicalFor(ptes)
+ physical, _, ok := translateToPhysical(virtual)
+ if !ok {
+ panic(fmt.Sprintf("PhysicalFor failed for %p", ptes))
+ }
+ return physical
+}
+
+// LookupPTEs implements pagetables.Allocator.LookupPTEs.
+//
+//go:nosplit
+func (a allocator) LookupPTEs(physical uintptr) *pagetables.PTEs {
+ virtualStart, physicalStart, _, ok := calculateBluepillFault(physical)
+ if !ok {
+ panic(fmt.Sprintf("LookupPTEs failed for 0x%x", physical))
+ }
+ return a.base.LookupPTEs(virtualStart + (physical - physicalStart))
+}
+
+// FreePTEs implements pagetables.Allocator.FreePTEs.
+//
+//go:nosplit
+func (a allocator) FreePTEs(ptes *pagetables.PTEs) {
+ a.base.FreePTEs(ptes)
+}
diff --git a/pkg/sentry/platform/kvm/bluepill_fault.go b/pkg/sentry/platform/kvm/bluepill_fault.go
index 7c8c7bc37..8650cd78f 100644
--- a/pkg/sentry/platform/kvm/bluepill_fault.go
+++ b/pkg/sentry/platform/kvm/bluepill_fault.go
@@ -46,7 +46,7 @@ func yield() {
// calculateBluepillFault calculates the fault address range.
//
//go:nosplit
-func calculateBluepillFault(m *machine, physical uintptr) (virtualStart, physicalStart, length uintptr, ok bool) {
+func calculateBluepillFault(physical uintptr) (virtualStart, physicalStart, length uintptr, ok bool) {
alignedPhysical := physical &^ uintptr(usermem.PageSize-1)
for _, pr := range physicalRegions {
end := pr.physical + pr.length
@@ -82,7 +82,7 @@ func handleBluepillFault(m *machine, physical uintptr) (uintptr, bool) {
// fault. This all has to be done in this function because we're in a
// signal handler context. (We can't call any functions that might
// split the stack.)
- virtualStart, physicalStart, length, ok := calculateBluepillFault(m, physical)
+ virtualStart, physicalStart, length, ok := calculateBluepillFault(physical)
if !ok {
return 0, false
}
diff --git a/pkg/sentry/platform/kvm/kvm.go b/pkg/sentry/platform/kvm/kvm.go
index 6defb1c46..13c363993 100644
--- a/pkg/sentry/platform/kvm/kvm.go
+++ b/pkg/sentry/platform/kvm/kvm.go
@@ -121,7 +121,7 @@ func (*KVM) MaxUserAddress() usermem.Addr {
// NewAddressSpace returns a new pagetable root.
func (k *KVM) NewAddressSpace(_ interface{}) (platform.AddressSpace, <-chan struct{}, error) {
// Allocate page tables and install system mappings.
- pageTables := k.machine.kernel.PageTables.New()
+ pageTables := k.machine.kernel.PageTables.New(newAllocator())
applyPhysicalRegions(func(pr physicalRegion) bool {
// Map the kernel in the upper half.
pageTables.Map(
diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go
index 5a6109ced..949abd838 100644
--- a/pkg/sentry/platform/kvm/machine.go
+++ b/pkg/sentry/platform/kvm/machine.go
@@ -133,7 +133,7 @@ func newMachine(vm int, vCPUs int) (*machine, error) {
vCPUs = n
}
m.kernel = ring0.New(ring0.KernelOpts{
- PageTables: pagetables.New(m, pagetablesOpts),
+ PageTables: pagetables.New(newAllocator(), pagetablesOpts),
})
// Initialize architecture state.
@@ -211,7 +211,7 @@ func newMachine(vm int, vCPUs int) (*machine, error) {
return // skip region.
}
for virtual := vr.virtual; virtual < vr.virtual+vr.length; {
- physical, length, ok := TranslateToPhysical(virtual)
+ physical, length, ok := translateToPhysical(virtual)
if !ok {
// This must be an invalid region that was
// knocked out by creation of the physical map.
@@ -239,7 +239,7 @@ func newMachine(vm int, vCPUs int) (*machine, error) {
// This panics on error.
func (m *machine) mapPhysical(physical, length uintptr) {
for end := physical + length; physical < end; {
- _, physicalStart, length, ok := calculateBluepillFault(m, physical)
+ _, physicalStart, length, ok := calculateBluepillFault(physical)
if !ok {
// Should never happen.
panic("mapPhysical on unknown physical address")
diff --git a/pkg/sentry/platform/kvm/machine_unsafe.go b/pkg/sentry/platform/kvm/machine_unsafe.go
index 516098a2b..86323c891 100644
--- a/pkg/sentry/platform/kvm/machine_unsafe.go
+++ b/pkg/sentry/platform/kvm/machine_unsafe.go
@@ -21,7 +21,6 @@ import (
"unsafe"
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
- "gvisor.googlesource.com/gvisor/pkg/sentry/platform/ring0/pagetables"
)
//go:linkname entersyscall runtime.entersyscall
@@ -30,17 +29,6 @@ func entersyscall()
//go:linkname exitsyscall runtime.exitsyscall
func exitsyscall()
-// TranslateToVirtual implements pagetables.Translater.TranslateToPhysical.
-func (m *machine) TranslateToPhysical(ptes *pagetables.PTEs) uintptr {
- // The length doesn't matter because all these translations require
- // only a single page, which is guaranteed to be satisfied.
- physical, _, ok := TranslateToPhysical(uintptr(unsafe.Pointer(ptes)))
- if !ok {
- panic("unable to translate pagetables.Node to physical address")
- }
- return physical
-}
-
// mapRunData maps the vCPU run data.
func mapRunData(fd int) (*runData, error) {
r, _, errno := syscall.RawSyscall6(
diff --git a/pkg/sentry/platform/kvm/physical_map.go b/pkg/sentry/platform/kvm/physical_map.go
index 5d55c9486..81a98656d 100644
--- a/pkg/sentry/platform/kvm/physical_map.go
+++ b/pkg/sentry/platform/kvm/physical_map.go
@@ -205,17 +205,19 @@ func applyPhysicalRegions(fn func(pr physicalRegion) bool) bool {
return true
}
-// TranslateToPhysical translates the given virtual address.
+// translateToPhysical translates the given virtual address.
//
// Precondition: physicalInit must have been called.
-func TranslateToPhysical(virtual uintptr) (physical uintptr, length uintptr, ok bool) {
- ok = !applyPhysicalRegions(func(pr physicalRegion) bool {
+//
+//go:nosplit
+func translateToPhysical(virtual uintptr) (physical uintptr, length uintptr, ok bool) {
+ for _, pr := range physicalRegions {
if pr.virtual <= virtual && virtual < pr.virtual+pr.length {
physical = pr.physical + (virtual - pr.virtual)
length = pr.length - (virtual - pr.virtual)
- return false
+ ok = true
+ return
}
- return true
- })
+ }
return
}