github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+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 }