github.com/platinasystems/nvram@v1.0.1-0.20190709235807-51a23abd5aec/coreboot_table.go (about) 1 package nvram 2 3 import ( 4 "fmt" 5 "github.com/platinasystems/nvram/debug" 6 "os" 7 "syscall" 8 "unsafe" 9 ) 10 11 type lbHeader struct { 12 signature uint32 13 headerBytes uint32 14 headerChecksum uint32 15 tableBytes uint32 16 tableChecksum uint32 17 tableEntries uint32 18 } 19 20 type lbRecord struct { 21 tag uint32 22 size uint32 23 } 24 25 type lbForward struct { 26 lbRecord 27 forward uint64 28 } 29 30 type cmosOptionTable struct { 31 lbRecord 32 headerLength uint32 33 } 34 35 type CoreBootTable struct { 36 mem_file *os.File 37 mem []byte 38 baseAddr uintptr 39 40 header *lbHeader 41 recs []*lbRecord 42 } 43 44 func (t *CoreBootTable) Open() (err error) { 45 defer func() { 46 if err != nil { 47 t.Close() 48 } 49 }() 50 51 t.mem_file, err = os.OpenFile("/dev/mem", os.O_RDONLY, 0) 52 if err != nil { 53 return 54 } 55 56 err = t.openTable(0x00000000, 0x00000fff) 57 if err != nil { 58 err = t.openTable(0x000f0000, 0x000fffff) 59 } 60 if err != nil { 61 return 62 } 63 64 return 65 } 66 67 func (t *CoreBootTable) Close() (err error) { 68 debug.Trace(debug.LevelMSG1, "Closing Coreboot table\n") 69 70 if len(t.mem) > 0 { 71 syscall.Munmap(t.mem) 72 t.mem = nil 73 } 74 75 if t.mem_file != nil { 76 t.mem_file.Close() 77 t.mem_file = nil 78 } 79 80 t.baseAddr = 0 81 t.header = nil 82 t.recs = nil 83 return 84 } 85 86 func (t *CoreBootTable) FindCMOSOptionTable() (c *cmosOptionTable, ok bool) { 87 for _, lbrec := range t.recs { 88 if lbrec.tag == 0xc8 { 89 return (*cmosOptionTable)(unsafe.Pointer(lbrec)), true 90 } 91 } 92 return nil, false 93 } 94 95 func (t *CoreBootTable) openTable(start, end uintptr) (err error) { 96 97 debug.Trace(debug.LevelMSG1, "Looking for table @0x%08X\n", start) 98 99 defer func() { 100 if err != nil { 101 t.header = nil 102 t.recs = nil 103 } 104 }() 105 106 t.mapPages(start, end) 107 108 for i := 0; i < len(t.mem); i += 16 { 109 var header = (*lbHeader)(unsafe.Pointer(&t.mem[i])) 110 if header.signature == 0x4f49424c { 111 debug.Trace(debug.LevelMSG1, "Table found @0x%08X\n", unsafe.Pointer(header)) 112 if t.computeIpChecksum(uintptr(unsafe.Pointer(header)), uint64(header.headerBytes)) != 0 { 113 debug.Trace(debug.LevelMSG1, "Header checksum bad\n") 114 continue 115 } 116 117 phyAddr := t.baseAddr + uintptr(i) 118 t.mapPages(phyAddr, phyAddr+uintptr(header.tableBytes)) 119 virtAddr := uintptr(unsafe.Pointer(&t.mem[0])) + phyAddr - t.baseAddr 120 header = (*lbHeader)(unsafe.Pointer(virtAddr)) 121 122 var lbrec = (*lbRecord)(unsafe.Pointer(virtAddr + uintptr(header.headerBytes))) 123 124 if t.computeIpChecksum(uintptr(unsafe.Pointer(lbrec)), uint64(header.tableBytes)) != header.tableChecksum { 125 debug.Trace(debug.LevelMSG1, "Table checksum bad\n") 126 continue 127 } 128 129 t.header = header 130 t.recs = nil 131 var lbforward *lbForward 132 for i := uint32(0); i < header.tableBytes; { 133 debug.Trace(debug.LevelMSG3, "Found lbRecord tag = %X len = %d\n", lbrec.tag, lbrec.size) 134 135 if lbforward == nil && lbrec.tag == 0x11 { 136 lbforward = (*lbForward)(unsafe.Pointer(lbrec)) 137 } 138 139 t.recs = append(t.recs, lbrec) 140 i += lbrec.size 141 lbrec = (*lbRecord)(unsafe.Pointer(uintptr(unsafe.Pointer(lbrec)) + uintptr(lbrec.size))) 142 } 143 144 if len(t.recs) != int(header.tableEntries) { 145 debug.Trace(debug.LevelMSG1, "Unexpected number of table entries.\n") 146 continue 147 } 148 149 if lbforward != nil { 150 debug.Trace(debug.LevelMSG1, "Forwarding table found.\n") 151 err = t.openTable(uintptr(lbforward.forward), uintptr(lbforward.forward)+uintptr(os.Getpagesize())) 152 return 153 } 154 155 return 156 } 157 } 158 159 err = fmt.Errorf("Coreboot table not found.") 160 return 161 } 162 163 func (t *CoreBootTable) mapPages(start, end uintptr) (err error) { 164 t.baseAddr = start 165 length := end - start 166 pagesize := uintptr(os.Getpagesize()) 167 168 numPages := (length + 169 (t.baseAddr & (pagesize - 1)) + 170 pagesize - 1) / pagesize 171 t.baseAddr &= ^(pagesize - 1) 172 173 if len(t.mem) > 0 { 174 syscall.Munmap(t.mem) 175 t.mem = nil 176 } 177 178 t.mem, err = syscall.Mmap(int(t.mem_file.Fd()), 179 int64(t.baseAddr), int(numPages*pagesize), 180 syscall.PROT_READ, syscall.MAP_SHARED) 181 if err != nil { 182 return 183 } 184 185 return 186 } 187 188 func (t *CoreBootTable) computeIpChecksum(start uintptr, length uint64) uint32 { 189 190 sum := uint32(0) 191 192 for i := start; i < (start + uintptr(length)); i++ { 193 ptr := (*byte)(unsafe.Pointer(i)) 194 value := uint32(*ptr) 195 if (i & 1) != 0 { 196 value <<= 8 197 } 198 199 sum += value 200 201 if sum > 0xFFFF { 202 sum = (sum + (sum >> 16)) & 0xFFFF 203 } 204 } 205 return (^sum) & 0xFFFF 206 }