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