github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/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 can find and parse the RSDP pointer and struct.
     6  package acpi
     7  
     8  import (
     9  	"bufio"
    10  	"encoding/binary"
    11  	"fmt"
    12  	"log"
    13  	"os"
    14  	"strconv"
    15  	"strings"
    16  
    17  	"github.com/u-root/u-root/pkg/boot/ebda"
    18  	"github.com/u-root/u-root/pkg/memio"
    19  )
    20  
    21  const (
    22  	// checksum1 offset in RSDP struct.
    23  	cSUM1Off = 8
    24  
    25  	// checksum2 offset in RSDP struct.
    26  	cSUM2Off    = 32
    27  	xSDTLenOff  = 20
    28  	xSDTAddrOff = 24
    29  
    30  	// headerLength is a common header length for (almost)
    31  	// all ACPI tables.
    32  	headerLength = 36
    33  )
    34  
    35  var (
    36  	defaultRSDP = []byte("RSDP PTR U-ROOT\x02")
    37  )
    38  
    39  // gencsum generates a uint8 checksum of a []uint8
    40  func gencsum(b []uint8) uint8 {
    41  	var csum uint8
    42  	for _, bb := range b {
    43  		csum += bb
    44  	}
    45  	return ^csum + 1
    46  }
    47  
    48  // RSDP is the v2 version of the ACPI RSDP struct.
    49  type RSDP struct {
    50  	// base is the base address of the RSDP struct in physical memory.
    51  	base uint64
    52  
    53  	data [headerLength]byte
    54  }
    55  
    56  // NewRSDP returns a new and partially initialized RSDP, setting only
    57  // the defaultRSDP values, address, length, and signature.
    58  func NewRSDP(addr uintptr, len uint) []byte {
    59  	var r [headerLength]byte
    60  	copy(r[:], defaultRSDP)
    61  
    62  	// This is a bit of a cheat. All the fields are 0.  So we get a
    63  	// checksum, set up the XSDT fields, get the second checksum.
    64  	r[cSUM1Off] = gencsum(r[:])
    65  	binary.LittleEndian.PutUint32(r[xSDTLenOff:], uint32(len))
    66  	binary.LittleEndian.PutUint64(r[xSDTAddrOff:], uint64(addr))
    67  	r[cSUM2Off] = gencsum(r[:])
    68  	return r[:]
    69  }
    70  
    71  // Len returns the RSDP length
    72  func (r *RSDP) Len() uint32 {
    73  	return uint32(len(r.data))
    74  }
    75  
    76  // AllData returns the RSDP as a []byte
    77  func (r *RSDP) AllData() []byte {
    78  	return r.data[:]
    79  }
    80  
    81  // TableData returns the RSDP table data as a []byte
    82  func (r *RSDP) TableData() []byte {
    83  	return r.data[36:]
    84  }
    85  
    86  // Sig returns the RSDP signature
    87  func (r *RSDP) Sig() string {
    88  	return string(r.data[:8])
    89  }
    90  
    91  // OEMID returns the RSDP OEMID
    92  func (r *RSDP) OEMID() string {
    93  	return string(r.data[9:15])
    94  }
    95  
    96  // RSDPAddr returns the physical base address of the RSDP.
    97  func (r *RSDP) RSDPAddr() uint64 {
    98  	return r.base
    99  }
   100  
   101  // SDTAddr returns a base address or the [RX]SDT.
   102  //
   103  // It will preferentially return the XSDT, but if that is
   104  // 0 it will return the RSDT address.
   105  func (r *RSDP) SDTAddr() uint64 {
   106  	b := uint64(binary.LittleEndian.Uint32(r.data[16:20]))
   107  	if b != 0 {
   108  		return b
   109  	}
   110  	return uint64(binary.LittleEndian.Uint64(r.data[24:32]))
   111  }
   112  
   113  func readRSDP(base uint64) (*RSDP, error) {
   114  	r := &RSDP{}
   115  	r.base = base
   116  
   117  	dat := memio.ByteSlice(make([]byte, len(r.data)))
   118  	if err := memio.Read(int64(base), &dat); err != nil {
   119  		return nil, err
   120  	}
   121  	copy(r.data[:], dat)
   122  	return r, nil
   123  }
   124  
   125  // GetRSDPEFI finds the RSDP in the EFI System Table.
   126  func GetRSDPEFI() (*RSDP, error) {
   127  	file, err := os.Open("/sys/firmware/efi/systab")
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	defer file.Close()
   132  
   133  	const (
   134  		acpi20 = "ACPI20="
   135  		acpi   = "ACPI="
   136  	)
   137  
   138  	scanner := bufio.NewScanner(file)
   139  	for scanner.Scan() {
   140  		line := scanner.Text()
   141  		start := ""
   142  		if strings.HasPrefix(line, acpi20) {
   143  			start = strings.TrimPrefix(line, acpi20)
   144  		}
   145  		if strings.HasPrefix(line, acpi) {
   146  			start = strings.TrimPrefix(line, acpi)
   147  		}
   148  		if start == "" {
   149  			continue
   150  		}
   151  		base, err := strconv.ParseUint(start, 0, 64)
   152  		if err != nil {
   153  			continue
   154  		}
   155  		rsdp, err := readRSDP(base)
   156  		if err != nil {
   157  			continue
   158  		}
   159  		return rsdp, nil
   160  	}
   161  	if err := scanner.Err(); err != nil {
   162  		log.Printf("error while reading EFI systab: %v", err)
   163  	}
   164  	return nil, fmt.Errorf("invalid /sys/firmware/efi/systab file")
   165  }
   166  
   167  // GetRSDPEBDA finds the RSDP in the EBDA.
   168  func GetRSDPEBDA() (*RSDP, error) {
   169  	f, err := os.OpenFile("/dev/mem", os.O_RDONLY, 0)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	defer f.Close()
   174  
   175  	e, err := ebda.ReadEBDA(f)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	return getRSDPMem(uint64(e.BaseOffset), uint64(e.BaseOffset+e.Length))
   181  }
   182  
   183  func getRSDPMem(start, end uint64) (*RSDP, error) {
   184  	for base := start; base < end; base += 16 {
   185  		var r memio.Uint64
   186  		if err := memio.Read(int64(base), &r); err != nil {
   187  			continue
   188  		}
   189  		if r != 0x2052545020445352 {
   190  			continue
   191  		}
   192  		rsdp, err := readRSDP(base)
   193  		if err != nil {
   194  			return nil, err
   195  		}
   196  		return rsdp, nil
   197  	}
   198  	return nil, fmt.Errorf("could not find ACPI RSDP via /dev/mem from %#08x to %#08x", start, end)
   199  }
   200  
   201  // GetRSDPMem is the option of last choice, it just grovels through
   202  // the e0000-ffff0 area, 16 bytes at a time, trying to find an RSDP.
   203  // These are well-known addresses for 20+ years.
   204  func GetRSDPMem() (*RSDP, error) {
   205  	return getRSDPMem(0xe0000, 0xffff0)
   206  }
   207  
   208  // You can change the getters if you wish for testing.
   209  var getters = []func() (*RSDP, error){GetRSDPEFI, GetRSDPEBDA, GetRSDPMem}
   210  
   211  // GetRSDP finds the RSDP pointer and struct in memory.
   212  //
   213  // It is able to use several methods, because there is no consistency
   214  // about how it is done.
   215  func GetRSDP() (*RSDP, error) {
   216  	for _, f := range getters {
   217  		r, err := f()
   218  		if err != nil {
   219  			log.Print(err)
   220  		}
   221  		if err == nil {
   222  			return r, nil
   223  		}
   224  	}
   225  	return nil, fmt.Errorf("cannot find an RSDP")
   226  }