github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/cmds/exp/fixrsdp/fixrsdp.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  // This command copies the existing RSDP into the EBDA. This is because
     6  // LinuxBoot tends to be EFI booted, which places the RSDP outside of the
     7  // low 1M or the EBDA. If Linuxboot legacy boots the following operating systems,
     8  // such as with kexec, they may not have a way to find the RSDP afterwards.
     9  // All u-root commands that open /dev/mem should also flock it to ensure safe,
    10  // sequential access
    11  package main
    12  
    13  import (
    14  	"bytes"
    15  	"log"
    16  	"os"
    17  	"syscall"
    18  
    19  	"github.com/u-root/u-root/pkg/acpi"
    20  	"github.com/u-root/u-root/pkg/ebda"
    21  )
    22  
    23  func main() {
    24  	// Find the RSDP.
    25  	base, r, err := acpi.GetRSDP()
    26  	if err != nil {
    27  		log.Fatalf("Unable to find system RSDP, got: %v", err)
    28  	}
    29  
    30  	rData := r.AllData()
    31  	rLen := len(rData)
    32  
    33  	// Check if ACPI rsdp is already in low memory
    34  	if base >= 0xe0000 && base+int64(rLen) < 0xffff0 {
    35  		log.Printf("RSDP is already in low memory at %#X, no need to fix.", base)
    36  		return
    37  	}
    38  
    39  	// Find the EBDA
    40  	f, err := os.OpenFile("/dev/mem", os.O_RDWR, 0)
    41  	if err != nil {
    42  		log.Fatal(err)
    43  	}
    44  	defer f.Close()
    45  
    46  	fd := int(f.Fd())
    47  	if err = syscall.Flock(fd, syscall.LOCK_EX); err != nil {
    48  		log.Fatal(err)
    49  	}
    50  	defer syscall.Flock(fd, syscall.LOCK_UN)
    51  
    52  	e, err := ebda.ReadEBDA(f)
    53  	if err != nil {
    54  		log.Fatal(err)
    55  	}
    56  	log.Printf("EBDA starts at %#X, length %#X bytes", e.BaseOffset, e.Length)
    57  
    58  	// Scan low 1K of EBDA for an empty spot that is 16 byte aligned
    59  	emptyStart := 0
    60  	for i := 16; i < (1024-rLen) && i < (int(e.Length)-rLen); i += 16 {
    61  		// Check if there's an empty spot to put the RSDP table.
    62  		if bytes.Equal(e.Data[i:i+rLen], make([]byte, rLen)) {
    63  			emptyStart = i
    64  			log.Printf("Found empty space at %#X offset into EBDA, will copy RSDP there", emptyStart)
    65  			break
    66  		}
    67  	}
    68  
    69  	if emptyStart == 0 {
    70  		log.Fatal("Unable to find empty space to put RSDP")
    71  	}
    72  
    73  	copy(e.Data[emptyStart:emptyStart+rLen], rData)
    74  
    75  	if err = ebda.WriteEBDA(e, f); err != nil {
    76  		log.Fatal(err)
    77  	}
    78  }