gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/ring0/pagetables/pagetables_test.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 pagetables 16 17 import ( 18 "testing" 19 20 "gvisor.dev/gvisor/pkg/hostarch" 21 ) 22 23 type mapping struct { 24 start uintptr 25 length uintptr 26 addr uintptr 27 opts MapOpts 28 } 29 30 type checkVisitor struct { 31 expected []mapping // Input. 32 current int // Temporary. 33 found []mapping // Output. 34 failed string // Output. 35 } 36 37 func (v *checkVisitor) visit(start uintptr, pte *PTE, align uintptr) bool { 38 v.found = append(v.found, mapping{ 39 start: start, 40 length: align + 1, 41 addr: pte.Address(), 42 opts: pte.Opts(), 43 }) 44 if v.failed != "" { 45 // Don't keep looking for errors. 46 return false 47 } 48 49 if v.current >= len(v.expected) { 50 v.failed = "more mappings than expected" 51 } else if v.expected[v.current].start != start { 52 v.failed = "start didn't match expected" 53 } else if v.expected[v.current].length != (align + 1) { 54 v.failed = "end didn't match expected" 55 } else if v.expected[v.current].addr != pte.Address() { 56 v.failed = "address didn't match expected" 57 } else if v.expected[v.current].opts != pte.Opts() { 58 v.failed = "opts didn't match" 59 } 60 v.current++ 61 return true 62 } 63 64 func (*checkVisitor) requiresAlloc() bool { return false } 65 66 func (*checkVisitor) requiresSplit() bool { return false } 67 68 func checkMappings(t *testing.T, pt *PageTables, m []mapping) { 69 // Iterate over all the mappings. 70 w := checkWalker{ 71 pageTables: pt, 72 visitor: checkVisitor{ 73 expected: m, 74 }, 75 } 76 w.iterateRange(0, ^uintptr(0)) 77 78 // Were we expected additional mappings? 79 if w.visitor.failed == "" && w.visitor.current != len(w.visitor.expected) { 80 w.visitor.failed = "insufficient mappings found" 81 } 82 83 // Emit a meaningful error message on failure. 84 if w.visitor.failed != "" { 85 t.Errorf("%s; got %#v, wanted %#v", w.visitor.failed, w.visitor.found, w.visitor.expected) 86 } 87 } 88 89 func TestUnmap(t *testing.T) { 90 pt := New(NewRuntimeAllocator()) 91 92 // Map and unmap one entry. 93 pt.Map(0x400000, pteSize, MapOpts{AccessType: hostarch.ReadWrite}, pteSize*42) 94 pt.Unmap(0x400000, pteSize) 95 96 checkMappings(t, pt, nil) 97 } 98 99 func TestReadOnly(t *testing.T) { 100 pt := New(NewRuntimeAllocator()) 101 102 // Map one entry. 103 pt.Map(0x400000, pteSize, MapOpts{AccessType: hostarch.Read}, pteSize*42) 104 105 checkMappings(t, pt, []mapping{ 106 {0x400000, pteSize, pteSize * 42, MapOpts{AccessType: hostarch.Read}}, 107 }) 108 } 109 110 func TestReadWrite(t *testing.T) { 111 pt := New(NewRuntimeAllocator()) 112 113 // Map one entry. 114 pt.Map(0x400000, pteSize, MapOpts{AccessType: hostarch.ReadWrite}, pteSize*42) 115 116 checkMappings(t, pt, []mapping{ 117 {0x400000, pteSize, pteSize * 42, MapOpts{AccessType: hostarch.ReadWrite}}, 118 }) 119 } 120 121 func TestSerialEntries(t *testing.T) { 122 pt := New(NewRuntimeAllocator()) 123 124 // Map two sequential entries. 125 pt.Map(0x400000, pteSize, MapOpts{AccessType: hostarch.ReadWrite}, pteSize*42) 126 pt.Map(0x401000, pteSize, MapOpts{AccessType: hostarch.ReadWrite}, pteSize*47) 127 128 checkMappings(t, pt, []mapping{ 129 {0x400000, pteSize, pteSize * 42, MapOpts{AccessType: hostarch.ReadWrite}}, 130 {0x401000, pteSize, pteSize * 47, MapOpts{AccessType: hostarch.ReadWrite}}, 131 }) 132 } 133 134 func TestSpanningEntries(t *testing.T) { 135 pt := New(NewRuntimeAllocator()) 136 137 // Span a pgd with two pages. 138 pt.Map(0x00007efffffff000, 2*pteSize, MapOpts{AccessType: hostarch.Read}, pteSize*42) 139 140 checkMappings(t, pt, []mapping{ 141 {0x00007efffffff000, pteSize, pteSize * 42, MapOpts{AccessType: hostarch.Read}}, 142 {0x00007f0000000000, pteSize, pteSize * 43, MapOpts{AccessType: hostarch.Read}}, 143 }) 144 } 145 146 func TestSparseEntries(t *testing.T) { 147 pt := New(NewRuntimeAllocator()) 148 149 // Map two entries in different pgds. 150 pt.Map(0x400000, pteSize, MapOpts{AccessType: hostarch.ReadWrite}, pteSize*42) 151 pt.Map(0x00007f0000000000, pteSize, MapOpts{AccessType: hostarch.Read}, pteSize*47) 152 153 checkMappings(t, pt, []mapping{ 154 {0x400000, pteSize, pteSize * 42, MapOpts{AccessType: hostarch.ReadWrite}}, 155 {0x00007f0000000000, pteSize, pteSize * 47, MapOpts{AccessType: hostarch.Read}}, 156 }) 157 }