github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/acpi/rsdp.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
     6  
     7  import (
     8  	"bufio"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"log"
    13  	"os"
    14  	"strconv"
    15  	"strings"
    16  
    17  	"github.com/u-root/u-root/pkg/memio"
    18  )
    19  
    20  const (
    21  	// Revision marks lowest ACPI revision we support.
    22  	Revision    = 2
    23  	cSUM1Off    = 8  // Checksum1 offset in packet.
    24  	cSUM2Off    = 32 // Checksum2 offset
    25  	xSDTLenOff  = 20
    26  	xSDTAddrOff = 24
    27  )
    28  
    29  var pageMask = uint64(os.Getpagesize() - 1)
    30  
    31  // RSDP is the v2 version of the RSDP struct, containing 32 and 64
    32  // bit pointers.
    33  // RSDP don't quite follow the ACPI table standard,
    34  // so some things return empty values. It has nevertheless proven
    35  // useful to have them.
    36  // We just define the RSDP for v2 and later here. It's the only
    37  // one that matters. This whole layout is typical of the overall
    38  // Failure Of Vision that is ACPI. 64-bit micros had existed for 10 years
    39  // when ACPI was defined, and they still wired in 32-bit pointer assumptions,
    40  // and had to backtrack and fix it later. We don't use this struct below,
    41  // it's only worthwhile as documentation. The RSDP has not changed in 20 years.
    42  type RSDP struct {
    43  	sign     [8]byte `Align:"16" Default:"RSDP PTR "`
    44  	v1CSUM   uint8   // This was the checksum, which we are pretty sure is ignored now.
    45  	oemid    [6]byte
    46  	revision uint8  `Default:"2"`
    47  	obase    uint32 // was RSDT, but you're not supposed to use it any more.
    48  	length   uint32
    49  	base     uint64 // XSDT address, the only one you should use
    50  	checksum uint8
    51  	_        [3]uint8
    52  	data     [HeaderLength]byte
    53  }
    54  
    55  var (
    56  	defaultRSDP = []byte("RSDP PTR U-ROOT\x02")
    57  	_           = Tabler(&RSDP{})
    58  )
    59  
    60  // Marshal fails to marshal an RSDP.
    61  func (r *RSDP) Marshal() ([]byte, error) {
    62  	return nil, fmt.Errorf("Marshal RSDP: not yet")
    63  }
    64  
    65  // NewRSDP returns a new and partially initialized RSDP, setting only
    66  // the defaultRSDP values, address, length, and signature.
    67  func NewRSDP(addr uintptr, len uint) []byte {
    68  	var r [HeaderLength]byte
    69  	copy(r[:], defaultRSDP)
    70  	// This is a bit of a cheat. All the fields are 0.
    71  	// So we get a checksum, set up the
    72  	// XSDT fields, get the second checksum.
    73  	r[cSUM1Off] = gencsum(r[:])
    74  	binary.LittleEndian.PutUint32(r[xSDTLenOff:], uint32(len))
    75  	binary.LittleEndian.PutUint64(r[xSDTAddrOff:], uint64(addr))
    76  	r[cSUM2Off] = gencsum(r[:])
    77  	return r[:]
    78  }
    79  
    80  // Len returns the RSDP length
    81  func (r *RSDP) Len() uint32 {
    82  	return uint32(len(r.data))
    83  }
    84  
    85  // AllData returns the RSDP as a []byte
    86  func (r *RSDP) AllData() []byte {
    87  	return r.data[:]
    88  }
    89  
    90  // TableData returns the RSDP table data as a []byte
    91  func (r *RSDP) TableData() []byte {
    92  	return r.data[36:]
    93  }
    94  
    95  // Sig returns the RSDP signature
    96  func (r *RSDP) Sig() string {
    97  	return string(r.data[:8])
    98  }
    99  
   100  // OEMID returns the RSDP OEMID
   101  func (r *RSDP) OEMID() string {
   102  	return string(r.data[9:15])
   103  }
   104  
   105  // OEMTableID returns the RSDP OEMTableID
   106  func (r *RSDP) OEMTableID() string {
   107  	return "rsdp?"
   108  }
   109  
   110  // Revision returns the RSDP revision, which
   111  // after 2002 should be >= 2
   112  func (r *RSDP) Revision() uint8 {
   113  	return r.revision
   114  }
   115  
   116  // OEMRevision returns the table OEMRevision.
   117  func (r *RSDP) OEMRevision() uint32 {
   118  	return 0
   119  }
   120  
   121  // CheckSum returns the table CheckSum.
   122  func (r *RSDP) CheckSum() uint8 {
   123  	return uint8(r.checksum)
   124  }
   125  
   126  // CreatorID returns the table CreatorID.
   127  func (r *RSDP) CreatorID() uint32 {
   128  	return uint32(0)
   129  }
   130  
   131  // CreatorRevision returns the table CreatorRevision.
   132  func (r *RSDP) CreatorRevision() uint32 {
   133  	return 0
   134  }
   135  
   136  // Base returns a base address or the [RX]SDT.
   137  // It will preferentially return the XSDT, but if that is
   138  // 0 it will return the RSDT address.
   139  func (r *RSDP) Base() int64 {
   140  	Debug("Base %v data len %d", r, len(r.data))
   141  	b := int64(binary.LittleEndian.Uint32(r.data[16:20]))
   142  	if b != 0 {
   143  		return b
   144  	}
   145  	return int64(binary.LittleEndian.Uint64(r.data[24:32]))
   146  }
   147  
   148  func readRSDP(base int64) (*RSDP, error) {
   149  	r := &RSDP{}
   150  	r.base = uint64(base)
   151  	dat := memio.ByteSlice(make([]byte, len(r.data)))
   152  	if err := memio.Read(base, &dat); err != nil {
   153  		return nil, err
   154  	}
   155  	copy(r.data[:], dat)
   156  	return r, nil
   157  }
   158  
   159  func getRSDPEFI() (int64, *RSDP, error) {
   160  	file, err := os.Open("/sys/firmware/efi/systab")
   161  	if err != nil {
   162  		return -1, nil, err
   163  	}
   164  	defer file.Close()
   165  
   166  	const (
   167  		acpi20 = "ACPI20="
   168  		acpi   = "ACPI="
   169  	)
   170  
   171  	scanner := bufio.NewScanner(file)
   172  	for scanner.Scan() {
   173  		line := scanner.Text()
   174  		start := ""
   175  		if strings.HasPrefix(line, acpi20) {
   176  			start = strings.TrimPrefix(line, acpi20)
   177  		}
   178  		if strings.HasPrefix(line, acpi) {
   179  			start = strings.TrimPrefix(line, acpi)
   180  		}
   181  		if start == "" {
   182  			continue
   183  		}
   184  		base, err := strconv.ParseInt(start, 0, 64)
   185  		if err != nil {
   186  			continue
   187  		}
   188  		rsdp, err := readRSDP(base)
   189  		if err != nil {
   190  			continue
   191  		}
   192  		return base, rsdp, nil
   193  	}
   194  	if err := scanner.Err(); err != nil {
   195  		log.Printf("error while reading EFI systab: %v", err)
   196  	}
   197  	return -1, nil, fmt.Errorf("invalid efi/systab file")
   198  }
   199  
   200  func num(n string, i int) (uint64, error) {
   201  	b, err := ioutil.ReadFile(fmt.Sprintf("/sys/firmware/memmap/%d/%s", i, n))
   202  	if err != nil {
   203  		return 0, err
   204  	}
   205  	start, err := strconv.ParseUint(string(b), 0, 64)
   206  	return start, err
   207  }
   208  
   209  // getRSDPmem is the option of last choice, it just grovels through
   210  // the e0000-ffff0 area, 16 bytes at a time, trying to find an RSDP.
   211  // These are well-known addresses for 20+ years.
   212  func getRSDPmem() (int64, *RSDP, error) {
   213  	for base := int64(0xe0000); base < 0xffff0; base += 16 {
   214  		var r memio.Uint64
   215  		if err := memio.Read(base, &r); err != nil {
   216  			continue
   217  		}
   218  		if r != 0x2052545020445352 {
   219  			continue
   220  		}
   221  		rsdp, err := readRSDP(base)
   222  		if err != nil {
   223  			return -1, nil, err
   224  		}
   225  		return base, rsdp, nil
   226  	}
   227  	return -1, nil, fmt.Errorf("No ACPI RSDP via /dev/mem")
   228  }
   229  
   230  // You can change the getters if you wish for testing.
   231  var getters = []func() (int64, *RSDP, error){getRSDPEFI, getRSDPmem}
   232  
   233  // GetRSDP gets an RSDP.
   234  // It is able to use several methods, because there is no consistency
   235  // about how it is done. The base is also returned.
   236  func GetRSDP() (base int64, rsdp *RSDP, err error) {
   237  	for _, f := range getters {
   238  		base, r, err := f()
   239  		if err != nil {
   240  			log.Print(err)
   241  		}
   242  		if err == nil {
   243  			return base, r, nil
   244  		}
   245  	}
   246  	return -1, nil, fmt.Errorf("Can't find an RSDP")
   247  }