2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-04-27 17:37:02 +00:00
|
|
|
//
|
|
|
|
// 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 memmap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MappingSet maps offsets into a Mappable to mappings of those offsets. It is
|
|
|
|
// used to implement Mappable.AddMapping and RemoveMapping for Mappables that
|
|
|
|
// may need to call MappingSpace.Invalidate.
|
|
|
|
//
|
|
|
|
// type MappingSet <generated by go_generics>
|
|
|
|
|
|
|
|
// MappingsOfRange is the value type of MappingSet, and represents the set of
|
|
|
|
// all mappings of the corresponding MappableRange.
|
|
|
|
//
|
|
|
|
// Using a map offers O(1) lookups in RemoveMapping and
|
|
|
|
// mappingSetFunctions.Merge.
|
|
|
|
type MappingsOfRange map[MappingOfRange]struct{}
|
|
|
|
|
|
|
|
// MappingOfRange represents a mapping of a MappableRange.
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-04-27 17:37:02 +00:00
|
|
|
type MappingOfRange struct {
|
|
|
|
MappingSpace MappingSpace
|
|
|
|
AddrRange usermem.AddrRange
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable bool
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r MappingOfRange) invalidate(opts InvalidateOpts) {
|
|
|
|
r.MappingSpace.Invalidate(r.AddrRange, opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
// String implements fmt.Stringer.String.
|
|
|
|
func (r MappingOfRange) String() string {
|
|
|
|
return fmt.Sprintf("%#v", r.AddrRange)
|
|
|
|
}
|
|
|
|
|
|
|
|
// mappingSetFunctions implements segment.Functions for MappingSet.
|
|
|
|
type mappingSetFunctions struct{}
|
|
|
|
|
|
|
|
// MinKey implements segment.Functions.MinKey.
|
|
|
|
func (mappingSetFunctions) MinKey() uint64 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxKey implements segment.Functions.MaxKey.
|
|
|
|
func (mappingSetFunctions) MaxKey() uint64 {
|
|
|
|
return math.MaxUint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClearValue implements segment.Functions.ClearValue.
|
|
|
|
func (mappingSetFunctions) ClearValue(v *MappingsOfRange) {
|
|
|
|
*v = MappingsOfRange{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Merge implements segment.Functions.Merge.
|
|
|
|
//
|
|
|
|
// Since each value is a map of MappingOfRanges, values can only be merged if
|
|
|
|
// all MappingOfRanges in each map have an exact pair in the other map, forming
|
|
|
|
// one contiguous region.
|
|
|
|
func (mappingSetFunctions) Merge(r1 MappableRange, val1 MappingsOfRange, r2 MappableRange, val2 MappingsOfRange) (MappingsOfRange, bool) {
|
|
|
|
if len(val1) != len(val2) {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
merged := make(MappingsOfRange, len(val1))
|
|
|
|
|
|
|
|
// Each MappingOfRange in val1 must have a matching region in val2, forming
|
|
|
|
// one contiguous region.
|
|
|
|
for k1 := range val1 {
|
2019-06-27 21:23:29 +00:00
|
|
|
// We expect val2 to contain a key that forms a contiguous
|
2018-04-27 17:37:02 +00:00
|
|
|
// region with k1.
|
|
|
|
k2 := MappingOfRange{
|
|
|
|
MappingSpace: k1.MappingSpace,
|
|
|
|
AddrRange: usermem.AddrRange{
|
|
|
|
Start: k1.AddrRange.End,
|
|
|
|
End: k1.AddrRange.End + usermem.Addr(r2.Length()),
|
|
|
|
},
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable: k1.Writable,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
if _, ok := val2[k2]; !ok {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK. Add it to the merged map.
|
|
|
|
merged[MappingOfRange{
|
|
|
|
MappingSpace: k1.MappingSpace,
|
|
|
|
AddrRange: usermem.AddrRange{
|
|
|
|
Start: k1.AddrRange.Start,
|
|
|
|
End: k2.AddrRange.End,
|
|
|
|
},
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable: k1.Writable,
|
2018-04-27 17:37:02 +00:00
|
|
|
}] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return merged, true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split implements segment.Functions.Split.
|
|
|
|
func (mappingSetFunctions) Split(r MappableRange, val MappingsOfRange, split uint64) (MappingsOfRange, MappingsOfRange) {
|
|
|
|
if split <= r.Start || split >= r.End {
|
|
|
|
panic(fmt.Sprintf("split is not within range %v", r))
|
|
|
|
}
|
|
|
|
|
|
|
|
m1 := make(MappingsOfRange, len(val))
|
|
|
|
m2 := make(MappingsOfRange, len(val))
|
|
|
|
|
|
|
|
// split is a value in MappableRange, we need the offset into the
|
|
|
|
// corresponding MappingsOfRange.
|
|
|
|
offset := usermem.Addr(split - r.Start)
|
|
|
|
for k := range val {
|
|
|
|
k1 := MappingOfRange{
|
|
|
|
MappingSpace: k.MappingSpace,
|
|
|
|
AddrRange: usermem.AddrRange{
|
|
|
|
Start: k.AddrRange.Start,
|
|
|
|
End: k.AddrRange.Start + offset,
|
|
|
|
},
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable: k.Writable,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
m1[k1] = struct{}{}
|
|
|
|
|
|
|
|
k2 := MappingOfRange{
|
|
|
|
MappingSpace: k.MappingSpace,
|
|
|
|
AddrRange: usermem.AddrRange{
|
|
|
|
Start: k.AddrRange.Start + offset,
|
|
|
|
End: k.AddrRange.End,
|
|
|
|
},
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable: k.Writable,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
m2[k2] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m1, m2
|
|
|
|
}
|
|
|
|
|
|
|
|
// subsetMapping returns the MappingOfRange that maps subsetRange, given that
|
|
|
|
// ms maps wholeRange beginning at addr.
|
|
|
|
//
|
|
|
|
// For instance, suppose wholeRange = [0x0, 0x2000) and addr = 0x4000,
|
|
|
|
// indicating that ms maps addresses [0x4000, 0x6000) to MappableRange [0x0,
|
|
|
|
// 0x2000). Then for subsetRange = [0x1000, 0x2000), subsetMapping returns a
|
|
|
|
// MappingOfRange for which AddrRange = [0x5000, 0x6000).
|
2018-12-12 21:09:10 +00:00
|
|
|
func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr usermem.Addr, writable bool) MappingOfRange {
|
2018-04-27 17:37:02 +00:00
|
|
|
if !wholeRange.IsSupersetOf(subsetRange) {
|
|
|
|
panic(fmt.Sprintf("%v is not a superset of %v", wholeRange, subsetRange))
|
|
|
|
}
|
|
|
|
|
|
|
|
offset := subsetRange.Start - wholeRange.Start
|
|
|
|
start := addr + usermem.Addr(offset)
|
|
|
|
return MappingOfRange{
|
|
|
|
MappingSpace: ms,
|
|
|
|
AddrRange: usermem.AddrRange{
|
|
|
|
Start: start,
|
|
|
|
End: start + usermem.Addr(subsetRange.Length()),
|
|
|
|
},
|
2018-12-12 21:09:10 +00:00
|
|
|
Writable: writable,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddMapping adds the given mapping and returns the set of MappableRanges that
|
|
|
|
// previously had no mappings.
|
|
|
|
//
|
|
|
|
// Preconditions: As for Mappable.AddMapping.
|
2018-12-12 21:09:10 +00:00
|
|
|
func (s *MappingSet) AddMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) []MappableRange {
|
2018-04-27 17:37:02 +00:00
|
|
|
mr := MappableRange{offset, offset + uint64(ar.Length())}
|
|
|
|
var mapped []MappableRange
|
|
|
|
seg, gap := s.Find(mr.Start)
|
|
|
|
for {
|
|
|
|
switch {
|
|
|
|
case seg.Ok() && seg.Start() < mr.End:
|
|
|
|
seg = s.Isolate(seg, mr)
|
2018-12-12 21:09:10 +00:00
|
|
|
seg.Value()[subsetMapping(mr, seg.Range(), ms, ar.Start, writable)] = struct{}{}
|
2018-04-27 17:37:02 +00:00
|
|
|
seg, gap = seg.NextNonEmpty()
|
|
|
|
|
|
|
|
case gap.Ok() && gap.Start() < mr.End:
|
|
|
|
gapMR := gap.Range().Intersect(mr)
|
|
|
|
mapped = append(mapped, gapMR)
|
|
|
|
// Insert a set and continue from the above case.
|
|
|
|
seg, gap = s.Insert(gap, gapMR, make(MappingsOfRange)), MappingGapIterator{}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return mapped
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveMapping removes the given mapping and returns the set of
|
|
|
|
// MappableRanges that now have no mappings.
|
|
|
|
//
|
|
|
|
// Preconditions: As for Mappable.RemoveMapping.
|
2018-12-12 21:09:10 +00:00
|
|
|
func (s *MappingSet) RemoveMapping(ms MappingSpace, ar usermem.AddrRange, offset uint64, writable bool) []MappableRange {
|
2018-04-27 17:37:02 +00:00
|
|
|
mr := MappableRange{offset, offset + uint64(ar.Length())}
|
|
|
|
var unmapped []MappableRange
|
|
|
|
|
|
|
|
seg := s.FindSegment(mr.Start)
|
|
|
|
if !seg.Ok() {
|
|
|
|
panic(fmt.Sprintf("MappingSet.RemoveMapping(%v): no segment containing %#x: %v", mr, mr.Start, s))
|
|
|
|
}
|
|
|
|
for seg.Ok() && seg.Start() < mr.End {
|
|
|
|
// Ensure this segment is limited to our range.
|
|
|
|
seg = s.Isolate(seg, mr)
|
|
|
|
|
|
|
|
// Remove this part of the mapping.
|
|
|
|
mappings := seg.Value()
|
2018-12-12 21:09:10 +00:00
|
|
|
delete(mappings, subsetMapping(mr, seg.Range(), ms, ar.Start, writable))
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
if len(mappings) == 0 {
|
|
|
|
unmapped = append(unmapped, seg.Range())
|
|
|
|
seg = s.Remove(seg).NextSegment()
|
|
|
|
} else {
|
|
|
|
seg = seg.NextSegment()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s.MergeAdjacent(mr)
|
|
|
|
return unmapped
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invalidate calls MappingSpace.Invalidate for all mappings of offsets in mr.
|
|
|
|
func (s *MappingSet) Invalidate(mr MappableRange, opts InvalidateOpts) {
|
|
|
|
for seg := s.LowerBoundSegment(mr.Start); seg.Ok() && seg.Start() < mr.End; seg = seg.NextSegment() {
|
|
|
|
segMR := seg.Range()
|
|
|
|
for m := range seg.Value() {
|
2018-12-12 21:09:10 +00:00
|
|
|
region := subsetMapping(segMR, segMR.Intersect(mr), m.MappingSpace, m.AddrRange.Start, m.Writable)
|
2018-04-27 17:37:02 +00:00
|
|
|
region.invalidate(opts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// InvalidateAll calls MappingSpace.Invalidate for all mappings of s.
|
|
|
|
func (s *MappingSet) InvalidateAll(opts InvalidateOpts) {
|
|
|
|
for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
|
|
|
|
for m := range seg.Value() {
|
|
|
|
m.invalidate(opts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|