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 }