github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/memmap/mapping_set.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memmap
    16  
    17  import (
    18  	"fmt"
    19  	"math"
    20  
    21  	"github.com/MerlinKodo/gvisor/pkg/hostarch"
    22  )
    23  
    24  // MappingSet maps offsets into a Mappable to mappings of those offsets. It is
    25  // used to implement Mappable.AddMapping and RemoveMapping for Mappables that
    26  // may need to call MappingSpace.Invalidate.
    27  //
    28  // type MappingSet <generated by go_generics>
    29  
    30  // MappingsOfRange is the value type of MappingSet, and represents the set of
    31  // all mappings of the corresponding MappableRange.
    32  //
    33  // Using a map offers O(1) lookups in RemoveMapping and
    34  // mappingSetFunctions.Merge.
    35  type MappingsOfRange map[MappingOfRange]struct{}
    36  
    37  // MappingOfRange represents a mapping of a MappableRange.
    38  //
    39  // +stateify savable
    40  type MappingOfRange struct {
    41  	MappingSpace MappingSpace
    42  	AddrRange    hostarch.AddrRange
    43  	Writable     bool
    44  }
    45  
    46  func (r MappingOfRange) invalidate(opts InvalidateOpts) {
    47  	r.MappingSpace.Invalidate(r.AddrRange, opts)
    48  }
    49  
    50  // String implements fmt.Stringer.String.
    51  func (r MappingOfRange) String() string {
    52  	return fmt.Sprintf("%#v", r.AddrRange)
    53  }
    54  
    55  // mappingSetFunctions implements segment.Functions for MappingSet.
    56  type mappingSetFunctions struct{}
    57  
    58  // MinKey implements segment.Functions.MinKey.
    59  func (mappingSetFunctions) MinKey() uint64 {
    60  	return 0
    61  }
    62  
    63  // MaxKey implements segment.Functions.MaxKey.
    64  func (mappingSetFunctions) MaxKey() uint64 {
    65  	return math.MaxUint64
    66  }
    67  
    68  // ClearValue implements segment.Functions.ClearValue.
    69  func (mappingSetFunctions) ClearValue(v *MappingsOfRange) {
    70  	*v = MappingsOfRange{}
    71  }
    72  
    73  // Merge implements segment.Functions.Merge.
    74  //
    75  // Since each value is a map of MappingOfRanges, values can only be merged if
    76  // all MappingOfRanges in each map have an exact pair in the other map, forming
    77  // one contiguous region.
    78  func (mappingSetFunctions) Merge(r1 MappableRange, val1 MappingsOfRange, r2 MappableRange, val2 MappingsOfRange) (MappingsOfRange, bool) {
    79  	if len(val1) != len(val2) {
    80  		return nil, false
    81  	}
    82  
    83  	merged := make(MappingsOfRange, len(val1))
    84  
    85  	// Each MappingOfRange in val1 must have a matching region in val2, forming
    86  	// one contiguous region.
    87  	for k1 := range val1 {
    88  		// We expect val2 to contain a key that forms a contiguous
    89  		// region with k1.
    90  		k2 := MappingOfRange{
    91  			MappingSpace: k1.MappingSpace,
    92  			AddrRange: hostarch.AddrRange{
    93  				Start: k1.AddrRange.End,
    94  				End:   k1.AddrRange.End + hostarch.Addr(r2.Length()),
    95  			},
    96  			Writable: k1.Writable,
    97  		}
    98  		if _, ok := val2[k2]; !ok {
    99  			return nil, false
   100  		}
   101  
   102  		// OK. Add it to the merged map.
   103  		merged[MappingOfRange{
   104  			MappingSpace: k1.MappingSpace,
   105  			AddrRange: hostarch.AddrRange{
   106  				Start: k1.AddrRange.Start,
   107  				End:   k2.AddrRange.End,
   108  			},
   109  			Writable: k1.Writable,
   110  		}] = struct{}{}
   111  	}
   112  
   113  	return merged, true
   114  }
   115  
   116  // Split implements segment.Functions.Split.
   117  func (mappingSetFunctions) Split(r MappableRange, val MappingsOfRange, split uint64) (MappingsOfRange, MappingsOfRange) {
   118  	if split <= r.Start || split >= r.End {
   119  		panic(fmt.Sprintf("split is not within range %v", r))
   120  	}
   121  
   122  	m1 := make(MappingsOfRange, len(val))
   123  	m2 := make(MappingsOfRange, len(val))
   124  
   125  	// split is a value in MappableRange, we need the offset into the
   126  	// corresponding MappingsOfRange.
   127  	offset := hostarch.Addr(split - r.Start)
   128  	for k := range val {
   129  		k1 := MappingOfRange{
   130  			MappingSpace: k.MappingSpace,
   131  			AddrRange: hostarch.AddrRange{
   132  				Start: k.AddrRange.Start,
   133  				End:   k.AddrRange.Start + offset,
   134  			},
   135  			Writable: k.Writable,
   136  		}
   137  		m1[k1] = struct{}{}
   138  
   139  		k2 := MappingOfRange{
   140  			MappingSpace: k.MappingSpace,
   141  			AddrRange: hostarch.AddrRange{
   142  				Start: k.AddrRange.Start + offset,
   143  				End:   k.AddrRange.End,
   144  			},
   145  			Writable: k.Writable,
   146  		}
   147  		m2[k2] = struct{}{}
   148  	}
   149  
   150  	return m1, m2
   151  }
   152  
   153  // subsetMapping returns the MappingOfRange that maps subsetRange, given that
   154  // ms maps wholeRange beginning at addr.
   155  //
   156  // For instance, suppose wholeRange = [0x0, 0x2000) and addr = 0x4000,
   157  // indicating that ms maps addresses [0x4000, 0x6000) to MappableRange [0x0,
   158  // 0x2000). Then for subsetRange = [0x1000, 0x2000), subsetMapping returns a
   159  // MappingOfRange for which AddrRange = [0x5000, 0x6000).
   160  func subsetMapping(wholeRange, subsetRange MappableRange, ms MappingSpace, addr hostarch.Addr, writable bool) MappingOfRange {
   161  	if !wholeRange.IsSupersetOf(subsetRange) {
   162  		panic(fmt.Sprintf("%v is not a superset of %v", wholeRange, subsetRange))
   163  	}
   164  
   165  	offset := subsetRange.Start - wholeRange.Start
   166  	start := addr + hostarch.Addr(offset)
   167  	return MappingOfRange{
   168  		MappingSpace: ms,
   169  		AddrRange: hostarch.AddrRange{
   170  			Start: start,
   171  			End:   start + hostarch.Addr(subsetRange.Length()),
   172  		},
   173  		Writable: writable,
   174  	}
   175  }
   176  
   177  // AddMapping adds the given mapping and returns the set of MappableRanges that
   178  // previously had no mappings.
   179  //
   180  // Preconditions: Same as Mappable.AddMapping.
   181  func (s *MappingSet) AddMapping(ms MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) []MappableRange {
   182  	mr := MappableRange{offset, offset + uint64(ar.Length())}
   183  	var mapped []MappableRange
   184  	seg, gap := s.Find(mr.Start)
   185  	for {
   186  		switch {
   187  		case seg.Ok() && seg.Start() < mr.End:
   188  			seg = s.Isolate(seg, mr)
   189  			seg.Value()[subsetMapping(mr, seg.Range(), ms, ar.Start, writable)] = struct{}{}
   190  			seg, gap = seg.NextNonEmpty()
   191  
   192  		case gap.Ok() && gap.Start() < mr.End:
   193  			gapMR := gap.Range().Intersect(mr)
   194  			mapped = append(mapped, gapMR)
   195  			// Insert a set and continue from the above case.
   196  			seg, gap = s.Insert(gap, gapMR, make(MappingsOfRange)), MappingGapIterator{}
   197  
   198  		default:
   199  			return mapped
   200  		}
   201  	}
   202  }
   203  
   204  // RemoveMapping removes the given mapping and returns the set of
   205  // MappableRanges that now have no mappings.
   206  //
   207  // Preconditions: Same as Mappable.RemoveMapping.
   208  func (s *MappingSet) RemoveMapping(ms MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) []MappableRange {
   209  	mr := MappableRange{offset, offset + uint64(ar.Length())}
   210  	var unmapped []MappableRange
   211  
   212  	seg := s.FindSegment(mr.Start)
   213  	if !seg.Ok() {
   214  		panic(fmt.Sprintf("MappingSet.RemoveMapping(%v): no segment containing %#x: %v", mr, mr.Start, s))
   215  	}
   216  	for seg.Ok() && seg.Start() < mr.End {
   217  		// Ensure this segment is limited to our range.
   218  		seg = s.Isolate(seg, mr)
   219  
   220  		// Remove this part of the mapping.
   221  		mappings := seg.Value()
   222  		delete(mappings, subsetMapping(mr, seg.Range(), ms, ar.Start, writable))
   223  
   224  		if len(mappings) == 0 {
   225  			unmapped = append(unmapped, seg.Range())
   226  			seg = s.Remove(seg).NextSegment()
   227  		} else {
   228  			seg = seg.NextSegment()
   229  		}
   230  	}
   231  	s.MergeAdjacent(mr)
   232  	return unmapped
   233  }
   234  
   235  // Invalidate calls MappingSpace.Invalidate for all mappings of offsets in mr.
   236  func (s *MappingSet) Invalidate(mr MappableRange, opts InvalidateOpts) {
   237  	for seg := s.LowerBoundSegment(mr.Start); seg.Ok() && seg.Start() < mr.End; seg = seg.NextSegment() {
   238  		segMR := seg.Range()
   239  		for m := range seg.Value() {
   240  			region := subsetMapping(segMR, segMR.Intersect(mr), m.MappingSpace, m.AddrRange.Start, m.Writable)
   241  			region.invalidate(opts)
   242  		}
   243  	}
   244  }
   245  
   246  // InvalidateAll calls MappingSpace.Invalidate for all mappings of s.
   247  func (s *MappingSet) InvalidateAll(opts InvalidateOpts) {
   248  	for seg := s.FirstSegment(); seg.Ok(); seg = seg.NextSegment() {
   249  		for m := range seg.Value() {
   250  			m.invalidate(opts)
   251  		}
   252  	}
   253  }