github.hscsec.cn/u-root/u-root@v7.0.0+incompatible/pkg/acpi/acpi.go (about)

     1  // Copyright 2019 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package acpi reads, modifies, and writes ACPI tables.
     6  //
     7  // acpi is designed to support copying individual tables or
     8  // a blob containing many tables from one spot to another, supporting
     9  // filtering. For example, one might read tables from /dev/mem, using
    10  // the RSDP, so as to create an ACPI table blob for use in coreboot.
    11  // In this case, we only care about checking the signature.
    12  package acpi
    13  
    14  import (
    15  	"bytes"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"io"
    19  )
    20  
    21  const (
    22  	// lengthOffset is the offset of the table length
    23  	lengthOffset = 4
    24  	// checksum1 offset in RSDP struct.
    25  	cSUM1Off = 8
    26  	// cSUMOffset is the offset of the single byte checksum in *most* ACPI tables
    27  	cSUMOffset = 9
    28  	// minTableLength is the minimum length: 4 byte tag, 4 byte length, 1 byte revision, 1 byte checksum,
    29  	minTableLength = 10
    30  
    31  	// checksum2 offset in RSDP struct.
    32  	cSUM2Off    = 32
    33  	xSDTLenOff  = 20
    34  	xSDTAddrOff = 24
    35  
    36  	// headerLength is a common header length for (almost)
    37  	// all ACPI tables.
    38  	headerLength = 36
    39  )
    40  
    41  type (
    42  	// Table is an individual ACPI table.
    43  	Table interface {
    44  		Sig() string
    45  		Len() uint32
    46  		Revision() uint8
    47  		CheckSum() uint8
    48  		OEMID() string
    49  		OEMTableID() string
    50  		OEMRevision() uint32
    51  		CreatorID() uint32
    52  		CreatorRevision() uint32
    53  		Data() []byte
    54  		TableData() []byte
    55  		Address() int64
    56  	}
    57  	// TableMethod defines the type of functions used to read a table.
    58  	TableMethod func() ([]Table, error)
    59  )
    60  
    61  // Debug enables various debug prints. External code can set it to, e.g., log.Printf
    62  var Debug = func(string, ...interface{}) {}
    63  
    64  // gencsum generates a uint8 checksum of a []uint8
    65  func gencsum(b []uint8) uint8 {
    66  	var csum uint8
    67  	for _, bb := range b {
    68  		csum += bb
    69  	}
    70  	return ^csum + 1
    71  }
    72  
    73  // getaddr gets an address, be it 64 or 32 bits, at the 64 or 32 bit offset, giving preference
    74  // to the 64-bit one.
    75  func getaddr(b []byte, addr64, addr32 int64) (int64, error) {
    76  	var a64 int64
    77  	if err := binary.Read(io.NewSectionReader(bytes.NewReader(b), addr64, 8), binary.LittleEndian, &a64); err == nil && a64 != 0 {
    78  		return a64, nil
    79  	}
    80  	var a32 int32
    81  	if err := binary.Read(io.NewSectionReader(bytes.NewReader(b), addr32, 4), binary.LittleEndian, &a32); err == nil {
    82  		return int64(a32), nil
    83  	}
    84  	return -1, fmt.Errorf("No 64-bit address at %d, no 32-bit address at %d, in %d-byte slice", addr64, addr32, len(b))
    85  }
    86  
    87  // Method accepts a method name and returns a TableMethod if one exists, or error othewise.
    88  func Method(n string) (TableMethod, error) {
    89  	f, ok := Methods[n]
    90  	if !ok {
    91  		return nil, fmt.Errorf("only method[s] %q are available, not %q", MethodNames(), n)
    92  	}
    93  	return f, nil
    94  }
    95  
    96  // String pretty-prints a Table
    97  func String(t Table) string {
    98  	return fmt.Sprintf("%s@%#x %d %d %#02x %s %s %#08x %#08x %#08x",
    99  		t.Sig(),
   100  		t.Address(),
   101  		t.Len(),
   102  		t.Revision(),
   103  		t.CheckSum(),
   104  		t.OEMID(),
   105  		t.OEMTableID(),
   106  		t.OEMRevision(),
   107  		t.CreatorID(),
   108  		t.CreatorRevision())
   109  
   110  }
   111  
   112  // WriteTables writes one or more tables to an io.Writer.
   113  func WriteTables(w io.Writer, tab Table, tabs ...Table) error {
   114  	for _, tt := range append([]Table{tab}, tabs...) {
   115  		if _, err := w.Write(tt.Data()); err != nil {
   116  			return fmt.Errorf("Writing %s: %v", tt.Sig(), err)
   117  		}
   118  	}
   119  	return nil
   120  }
   121  
   122  // ReadTables reads tables, given a method name.
   123  func ReadTables(n string) ([]Table, error) {
   124  	f, err := Method(n)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return f()
   129  }