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