github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+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 began life as a relatively simple set of functions.
     6  // At some point we wanted to be able to extend the ACPI table over a
     7  // kexec and that's when it all went nasty.
     8  // A few issues crop up.
     9  // In theory, one should be able to put tables anywhere. In practice,
    10  // even in the EFI age, this is not simple. The root pointer
    11  // for tables, RSDP, Root Services Data Pointer, is in memory protected by
    12  // the southbridge/ICH/PCH with lockdown bits (disable writes once, can
    13  // not be reset until power on/reset). Writes to it are transparently discarded.
    14  // (This makes sense, as crap DOS programs probably tried to write that area all
    15  // the time. Everything -- everything! -- about x86 and BIOS is explainable
    16  // by DOS, 16 bit addresses, 4 bit segments, 20 bits, and the incredible failure
    17  // of vision in 1999 of building a bunch of tables with 32 bit pointers in them.
    18  // The x86 world is nothing if not consistent: short-sighted decisions for 40+ years).
    19  // The two-byte EBDA pointer (16 bits) is shifted left 4 bits to get a 20-bit address
    20  // which points to *the range of memory* containing, maybe, the RSDP.
    21  // The RSDP has to live in the low 20 bits of address space (remember 20 bits, right?)
    22  // (Yes, I know about the EFI tables which make this restriction less of a problem,
    23  //  but for now all the firmware I've seen adheres to the "RSDP in e or f segment" rule.)
    24  // The RSDP has two pointers in it, one or both containing a value: 32 bit pointer or 64 bit
    25  // pointer to the RSDT or XSDT. (see "failure of vision" above.)
    26  // RSDT has 32-bit pointers, XSDT 64-bit pointers.
    27  // The spec recommends you ignore the 32-bit pointer variants but as of 2019,
    28  // I still see use of them; this package will read and write the variants but the
    29  // internal structs are defined with 64-bit pointers (oh, if only the ACPICA code
    30  // had gotten this right, but that code is pretty bad too).
    31  // What's really fun: when you generate the [RX]SDT, you need to generate pointers
    32  // too. It's best to keep those tables in a physically contiguous area, so we do;
    33  // not all systems follow this rule, which is asking for trouble.
    34  // Finally, not all tables are generated in a consistent way, e.g. the IBFT is not like
    35  // most other tables containing variable length data, because the people who created it
    36  // are Klever. IBFT has its own heap, and the elements in the heap follow rules unlike
    37  // all other tables. Nice!
    38  // If you really look at ACPI closely, you can kind of see that it's optimized for NASM,
    39  // which is part of what makes it so unpleasant. But, it's what we have.
    40  package acpi
    41  
    42  import (
    43  	"bytes"
    44  	"encoding/binary"
    45  	"fmt"
    46  	"log"
    47  	"strconv"
    48  )
    49  
    50  const (
    51  	// LengthOffset is the offset of the table length
    52  	LengthOffset = 4
    53  	// CSUMOffset is the offset of the single byte checksum in *most* ACPI tables
    54  	CSUMOffset = 9
    55  	// MinTableLength is the minimum length: 4 byte tag, 4 byte length, 1 byte revision, 1 byte checksum,
    56  	MinTableLength = 10
    57  )
    58  
    59  var (
    60  	// Debug implements fmt.Sprintf and can be used for debug printing
    61  	Debug        = func(string, ...interface{}) {}
    62  	unmarshalers = map[sig]func(Tabler) (Tabler, error){}
    63  )
    64  
    65  // addUnMarshaler is intended to be called by init functions
    66  // in this package. It adds an UnMarshaler for a given
    67  // ACPI signature.
    68  func addUnMarshaler(n string, f func(Tabler) (Tabler, error)) {
    69  	if _, ok := unmarshalers[sig(n)]; ok {
    70  		log.Fatalf("Can't add %s; already in use", n)
    71  	}
    72  	unmarshalers[sig(n)] = f
    73  }
    74  
    75  // GetHeader extracts a Header from a Tabler and returns a reference to it.
    76  func GetHeader(t Tabler) *Header {
    77  	return &Header{
    78  		Sig:             sig(t.Sig()),
    79  		Length:          t.Len(),
    80  		Revision:        t.Revision(),
    81  		CheckSum:        t.CheckSum(),
    82  		OEMID:           oem(t.OEMID()),
    83  		OEMTableID:      tableid(t.OEMTableID()),
    84  		OEMRevision:     t.OEMRevision(),
    85  		CreatorID:       t.CreatorID(),
    86  		CreatorRevision: t.CreatorRevision(),
    87  	}
    88  }
    89  
    90  // Flags takes 0 or more flags and produces a uint8 value.
    91  // Each argument represents one bit position, with the first flag
    92  // being bit 0. For each flag with a value of "1", the bit for that
    93  // flag will be set. For each flag with a value of "0", that bit in
    94  // the flag will be cleared.
    95  // This is mainly for consistency but it would allow
    96  // us in future to pass in an initial value and set or clear bits in it
    97  // depending on flags.
    98  // Current allowed values are "0" and "1". In future, if the flags are
    99  // not contiguous, we can allow "ignore" in future to ignore a flag.
   100  func flags(s ...flag) (uint8, error) {
   101  	var i, bit uint8
   102  	for _, f := range s {
   103  		switch f {
   104  		case "1":
   105  			i |= 1 << bit
   106  		case "0":
   107  			i &= ^(1 << bit)
   108  		default:
   109  			return 0, fmt.Errorf("%s is not a valid value: only 0 or 1 are valid", f)
   110  		}
   111  		bit++
   112  	}
   113  	return i, nil
   114  }
   115  
   116  // w writes 0 or more values to a bytes.Buffer, in LittleEndian order.
   117  func w(b *bytes.Buffer, val ...interface{}) {
   118  	for _, v := range val {
   119  		binary.Write(b, binary.LittleEndian, v)
   120  		Debug("\t %T %v b is %d bytes", v, v, b.Len())
   121  	}
   122  	Debug("w: done: b is %d bytes", b.Len())
   123  }
   124  
   125  // uw writes strings as unsigned words to a bytes.Buffer.
   126  // Currently it only supports 16, 32, and 64 bit writes.
   127  func uw(b *bytes.Buffer, s string, bits int) error {
   128  	// convenience case: if they don't set it, it comes in as "",
   129  	// take that to mean 0.
   130  	var v uint64
   131  	if s != "" {
   132  		var err error
   133  		if v, err = strconv.ParseUint(string(s), 0, bits); err != nil {
   134  			return err
   135  		}
   136  	}
   137  	switch bits {
   138  	case 8:
   139  		w(b, uint8(v))
   140  	case 16:
   141  		w(b, uint16(v))
   142  	case 32:
   143  		w(b, uint32(v))
   144  	case 64:
   145  		w(b, uint64(v))
   146  	default:
   147  		return fmt.Errorf("Invalid bit length for uw: %d, only supoprt 8, 16, 32, 64", bits)
   148  	}
   149  	return nil
   150  }
   151  
   152  // Marshal marshals a Tabler into a byte slice.
   153  // Once marshaling is done, it inserts the length into
   154  // the standard place at LengthOffset, and then generates and inserts
   155  // a checksum at CSUMOffset.
   156  func Marshal(t Tabler) ([]byte, error) {
   157  	Debug("Marshal %T", t)
   158  	b, err := t.Marshal()
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	if len(b) < MinTableLength {
   164  		return nil, fmt.Errorf("%v is too short to contain a table", b)
   165  	}
   166  
   167  	binary.LittleEndian.PutUint32(b[LengthOffset:], uint32(len(b)))
   168  	c := gencsum(b)
   169  	Debug("CSUM is %#x", c)
   170  	b[CSUMOffset] = c
   171  
   172  	return b, nil
   173  }
   174  
   175  // UnMarshal unmarshals a single table and returns a Tabler.
   176  // If the table is one of the many we don't care about we
   177  // just return a Raw table, which can be easily written out
   178  // again if needed. If it has an UnMarshal registered we use
   179  // that instead once the Raw is unmarshaled.
   180  func UnMarshal(a int64) (Tabler, error) {
   181  	r, err := ReadRaw(a)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	Debug("Raw table: %q", r)
   186  	if m, ok := unmarshalers[sig(r.Sig())]; ok {
   187  		return m(r)
   188  	}
   189  
   190  	return r, nil
   191  }
   192  
   193  // UnMarshalSDT unmarshals an SDT.
   194  // It's pretty much impossible for the RSDP to point to
   195  // anything else so we mainly do the unmarshal and type assertion.
   196  func UnMarshalSDT(r *RSDP) (*SDT, error) {
   197  	s, err := UnMarshal(r.Base())
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	Debug("SDT: %q", s)
   202  	return s.(*SDT), nil
   203  }
   204  
   205  // UnMarshalAll takes an SDT and unmarshals all the tables
   206  // using UnMarshal. It returns a []Tabler. In most cases,
   207  // the tables will be Raw, but in a few cases they might be
   208  // further converted.
   209  func UnMarshalAll(s *SDT) ([]Tabler, error) {
   210  	var tab []Tabler
   211  	for _, a := range s.Tables {
   212  		t, err := UnMarshal(a)
   213  		if err != nil {
   214  			return nil, err
   215  		}
   216  		tab = append(tab, t)
   217  	}
   218  
   219  	return tab, nil
   220  }