github.com/platinasystems/nvram@v1.0.1-0.20190709235807-51a23abd5aec/layout_bin.go (about) 1 package nvram 2 3 import ( 4 "fmt" 5 "os" 6 "syscall" 7 "unsafe" 8 ) 9 10 type cmosEntryTableRecord struct { 11 lbRecord 12 bit uint32 13 length uint32 14 config uint32 15 configId uint32 16 name [32]byte 17 } 18 19 type cmosEnumTableRecord struct { 20 lbRecord 21 configId uint32 22 value uint32 23 text [32]byte 24 } 25 26 type cmosChecksumTableRecord struct { 27 lbRecord 28 rangeStart uint32 29 rangeEnd uint32 30 location uint32 31 checksumType uint32 32 } 33 34 func ReadLayoutFromCMOSTable(table *cmosOptionTable) (layout *Layout, err error) { 35 // Check that we have a valid CMOS Option table 36 if table == nil || table.tag != 200 { 37 err = fmt.Errorf("Not a valid CMOS Option Table") 38 return 39 } 40 41 // Create a new empty CMOS layout. 42 layout = NewLayout() 43 44 // Set address into option table after table header. 45 var address = uintptr(unsafe.Pointer(table)) + uintptr(table.headerLength) 46 var endAddress = address + uintptr(table.size-table.headerLength) 47 48 for { 49 // Continue looking for table records till end of table data. 50 if address >= endAddress { 51 break 52 } 53 54 // Look at current table record 55 var lbrec = (*lbRecord)(unsafe.Pointer(address)) 56 57 switch lbrec.tag { 58 // Decode CMOS entry Table Record 59 case 201: 60 var rec = (*cmosEntryTableRecord)(unsafe.Pointer(lbrec)) 61 var entry CMOSEntry 62 63 // Read values for CMOS Entry 64 entry.bit = uint(rec.bit) 65 entry.length = uint(rec.length) 66 entry.config = CMOSEntryConfig(rec.config) 67 entry.config_id = uint(rec.configId) 68 69 // Copy string from table entry 70 for _, v := range rec.name { 71 if v == 0 { 72 break 73 } 74 entry.name = entry.name + string(v) 75 } 76 77 // Add CMOS entry to layout 78 err = layout.AddCMOSEntry(&entry) 79 if err != nil { 80 return 81 } 82 83 // Decode CMOS Enumeration Record 84 case 202: 85 var rec = (*cmosEnumTableRecord)(unsafe.Pointer(lbrec)) 86 var item CMOSEnumItem 87 88 // Read values for CMOS enumeration 89 item.id = uint(rec.configId) 90 item.value = uint(rec.value) 91 92 // Copy string from table entry 93 for _, v := range rec.text { 94 if v == 0 { 95 break 96 } 97 item.text = item.text + string(v) 98 } 99 100 // Check if enumeration value already exists for an id. 101 _, ok := layout.FindCMOSEnumText(item.id, item.value) 102 if ok { 103 fmt.Errorf("Enum %d already exists for id %d", 104 item.id, item.value) 105 return 106 } 107 108 // Add CMOS enumeration to layout 109 layout.AddCMOSEnum(&item) 110 111 // Decode CMOS Checksum Record 112 case 204: 113 var rec = (*cmosChecksumTableRecord)(unsafe.Pointer(lbrec)) 114 115 // Read and check CMOS checksum info. 116 layout.cmosChecksum, err = NewCMOSChecksum(uint(rec.rangeStart), 117 uint(rec.rangeEnd), uint(rec.location)) 118 if err != nil { 119 return 120 } 121 } 122 123 // Move to next table record 124 address += uintptr(lbrec.size) 125 } 126 127 return 128 } 129 130 func ReadLayoutFromCMOSTableBinary(filename string) (layout *Layout, err error) { 131 var mem_file *os.File 132 var mem []byte 133 134 // Unmap and close CMOS Option table file. 135 defer func() { 136 if len(mem) > 0 { 137 syscall.Munmap(mem) 138 mem = nil 139 } 140 141 if mem_file != nil { 142 mem_file.Close() 143 mem_file = nil 144 } 145 }() 146 147 // Open CMOS option table file 148 mem_file, err = os.OpenFile(filename, os.O_RDONLY, 0) 149 if err != nil { 150 return 151 } 152 153 fi, err := mem_file.Stat() 154 if err != nil { 155 return 156 } 157 size := fi.Size() 158 159 if size < 0 { 160 err = fmt.Errorf("File %s has negative size.", filename) 161 return 162 } 163 164 // Map CMOS option table 165 mem, err = syscall.Mmap(int(mem_file.Fd()), 0, int(size), 166 syscall.PROT_READ, syscall.MAP_SHARED) 167 if err != nil { 168 return 169 } 170 171 172 // Read CMOS Option table and create layout 173 return ReadLayoutFromCMOSTable((*cmosOptionTable)(unsafe.Pointer(&mem[0]))) 174 } 175 176 func ReadLayoutFromCoreBootTable() (layout *Layout, err error) { 177 var cbtable CoreBootTable 178 179 // Close coreboot able 180 defer func() { 181 cbtable.Close() 182 }() 183 184 // Open coreboot table 185 err = cbtable.Open() 186 if err != nil { 187 return 188 } 189 190 // Find the CMOS Option table in the coreboot table 191 optionTable, ok := cbtable.FindCMOSOptionTable() 192 if !ok { 193 err = fmt.Errorf("CMOS Option Table not found") 194 return 195 } 196 197 // Read layout from CMOS Option table 198 return ReadLayoutFromCMOSTable(optionTable) 199 200 }