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  }