185 lines
5.1 KiB
Go
185 lines
5.1 KiB
Go
// 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"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
|
|
)
|
|
|
|
type hostMap struct {
|
|
// mu protects below.
|
|
mu sync.RWMutex
|
|
|
|
// set contains host mappings.
|
|
set hostMapSet
|
|
}
|
|
|
|
type hostMapEntry struct {
|
|
addr uintptr
|
|
length uintptr
|
|
}
|
|
|
|
// forEach iterates over all mappings in the given range.
|
|
//
|
|
// Precondition: segFn and gapFn must be non-nil.
|
|
func (hm *hostMap) forEach(
|
|
r usermem.AddrRange,
|
|
segFn func(offset uint64, m hostMapEntry),
|
|
gapFn func(offset uint64, length uintptr) (uintptr, bool)) {
|
|
|
|
seg, gap := hm.set.Find(r.Start)
|
|
for {
|
|
if seg.Ok() && seg.Start() < r.End {
|
|
// A valid segment: pass information.
|
|
overlap := seg.Range().Intersect(r)
|
|
segOffset := uintptr(overlap.Start - seg.Start())
|
|
mapOffset := uint64(overlap.Start - r.Start)
|
|
segFn(mapOffset, hostMapEntry{
|
|
addr: seg.Value() + segOffset,
|
|
length: uintptr(overlap.Length()),
|
|
})
|
|
seg, gap = seg.NextNonEmpty()
|
|
} else if gap.Ok() && gap.Start() < r.End {
|
|
// A gap: pass gap information.
|
|
overlap := gap.Range().Intersect(r)
|
|
mapOffset := uint64(overlap.Start - r.Start)
|
|
addr, ok := gapFn(mapOffset, uintptr(overlap.Length()))
|
|
if ok {
|
|
seg = hm.set.Insert(gap, overlap, addr)
|
|
seg, gap = seg.NextNonEmpty()
|
|
} else {
|
|
seg = gap.NextSegment()
|
|
gap = hostMapGapIterator{} // Invalid.
|
|
}
|
|
} else {
|
|
// Terminal.
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (hm *hostMap) createMappings(r usermem.AddrRange, at usermem.AccessType, fd int, offset uint64) (ms []hostMapEntry, err error) {
|
|
hm.forEach(r, func(mapOffset uint64, m hostMapEntry) {
|
|
// Replace any existing mappings.
|
|
_, _, errno := syscall.RawSyscall6(
|
|
syscall.SYS_MMAP,
|
|
m.addr,
|
|
m.length,
|
|
uintptr(at.Prot()),
|
|
syscall.MAP_FIXED|syscall.MAP_SHARED,
|
|
uintptr(fd),
|
|
uintptr(offset+mapOffset))
|
|
if errno != 0 && err == nil {
|
|
err = errno
|
|
}
|
|
}, func(mapOffset uint64, length uintptr) (uintptr, bool) {
|
|
// Create a new mapping.
|
|
addr, _, errno := syscall.RawSyscall6(
|
|
syscall.SYS_MMAP,
|
|
0,
|
|
length,
|
|
uintptr(at.Prot()),
|
|
syscall.MAP_SHARED,
|
|
uintptr(fd),
|
|
uintptr(offset+mapOffset))
|
|
if errno != 0 {
|
|
err = errno
|
|
return 0, false
|
|
}
|
|
return addr, true
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Collect all entries.
|
|
//
|
|
// We do this after the first iteration because some segments may have
|
|
// been merged in the above, and we'll return the simplest form. This
|
|
// also provides a basic sanity check in the form of no gaps.
|
|
hm.forEach(r, func(_ uint64, m hostMapEntry) {
|
|
ms = append(ms, m)
|
|
}, func(uint64, uintptr) (uintptr, bool) {
|
|
// Should not happen: we just mapped this above.
|
|
panic("unexpected gap")
|
|
})
|
|
|
|
return ms, nil
|
|
}
|
|
|
|
// CreateMappings creates a new set of host mapping entries.
|
|
func (hm *hostMap) CreateMappings(r usermem.AddrRange, at usermem.AccessType, fd int, offset uint64) (ms []hostMapEntry, err error) {
|
|
hm.mu.Lock()
|
|
ms, err = hm.createMappings(r, at, fd, offset)
|
|
hm.mu.Unlock()
|
|
return
|
|
}
|
|
|
|
func (hm *hostMap) deleteMapping(r usermem.AddrRange) {
|
|
// Remove all the existing mappings.
|
|
hm.forEach(r, func(_ uint64, m hostMapEntry) {
|
|
_, _, errno := syscall.RawSyscall(
|
|
syscall.SYS_MUNMAP,
|
|
m.addr,
|
|
m.length,
|
|
0)
|
|
if errno != 0 {
|
|
// Should never happen.
|
|
panic(fmt.Sprintf("unmap error: %v", errno))
|
|
}
|
|
}, func(uint64, uintptr) (uintptr, bool) {
|
|
// Sometimes deleteMapping will be called on a larger range
|
|
// than physical mappings are defined. That's okay.
|
|
return 0, false
|
|
})
|
|
|
|
// Knock the entire range out.
|
|
hm.set.RemoveRange(r)
|
|
}
|
|
|
|
// DeleteMapping deletes the given range.
|
|
func (hm *hostMap) DeleteMapping(r usermem.AddrRange) {
|
|
hm.mu.Lock()
|
|
hm.deleteMapping(r)
|
|
hm.mu.Unlock()
|
|
}
|
|
|
|
// hostMapSetFunctions is used in the implementation of mapSet.
|
|
type hostMapSetFunctions struct{}
|
|
|
|
func (hostMapSetFunctions) MinKey() usermem.Addr { return 0 }
|
|
func (hostMapSetFunctions) MaxKey() usermem.Addr { return ^usermem.Addr(0) }
|
|
func (hostMapSetFunctions) ClearValue(val *uintptr) { *val = 0 }
|
|
|
|
func (hostMapSetFunctions) Merge(r1 usermem.AddrRange, addr1 uintptr, r2 usermem.AddrRange, addr2 uintptr) (uintptr, bool) {
|
|
if addr1+uintptr(r1.Length()) != addr2 {
|
|
return 0, false
|
|
}
|
|
|
|
// Since the two regions are contiguous in both the key space and the
|
|
// value space, we can just store a single segment with the first host
|
|
// virtual address; the logic above operates based on the size of the
|
|
// segments.
|
|
return addr1, true
|
|
}
|
|
|
|
func (hostMapSetFunctions) Split(r usermem.AddrRange, hostAddr uintptr, split usermem.Addr) (uintptr, uintptr) {
|
|
return hostAddr, hostAddr + uintptr(split-r.Start)
|
|
}
|