gitee.com/mirrors_u-root/u-root@v7.0.0+incompatible/pkg/boot/multiboot/internal/trampoline/trampoline_linux_amd64.go (about)

     1  // Copyright 2018 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 trampoline sets machine to a specific state defined by multiboot v1
     6  // spec and jumps to the intended kernel.
     7  //
     8  // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Machine-state.
     9  package trampoline
    10  
    11  import (
    12  	"io"
    13  	"reflect"
    14  	"unsafe"
    15  
    16  	"github.com/u-root/u-root/pkg/ubinary"
    17  )
    18  
    19  const (
    20  	trampolineEntry = "u-root-entry-long"
    21  	trampolineInfo  = "u-root-info-long"
    22  	trampolineMagic = "u-root-mb-magic"
    23  )
    24  
    25  func start()
    26  func end()
    27  func info()
    28  func magic()
    29  func entry()
    30  
    31  // funcPC gives the program counter of the given function.
    32  //
    33  //go:linkname funcPC runtime.funcPC
    34  func funcPC(f interface{}) uintptr
    35  
    36  // Setup scans file for trampoline code and sets
    37  // values for multiboot info address and kernel entry point.
    38  func Setup(path string, magic, infoAddr, entryPoint uintptr) ([]byte, error) {
    39  	trampolineStart, d, err := extract(path)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	return patch(trampolineStart, d, magic, infoAddr, entryPoint)
    44  }
    45  
    46  // extract extracts trampoline segment from file.
    47  // trampoline segment begins after "u-root-trampoline-begin" byte sequence + padding,
    48  // and ends at "u-root-trampoline-end" byte sequence.
    49  func extract(path string) (uintptr, []byte, error) {
    50  	// TODO(https://github.com/golang/go/issues/35055): deal with
    51  	// potentially non-contiguous trampoline. Rather than locating start
    52  	// and end, we should locate start,boot,farjump{32,64},gdt,info,entry
    53  	// individually and return one potentially really big trampoline slice.
    54  	tbegin := funcPC(start)
    55  	tend := funcPC(end)
    56  	if tend <= tbegin {
    57  		return 0, nil, io.ErrUnexpectedEOF
    58  	}
    59  	tramp := ptrToSlice(tbegin, int(tend-tbegin))
    60  
    61  	// tramp is read-only executable memory. So we gotta copy it to a
    62  	// slice. Gotta modify it later.
    63  	cp := append([]byte(nil), tramp...)
    64  	return tbegin, cp, nil
    65  }
    66  
    67  func ptrToSlice(ptr uintptr, size int) []byte {
    68  	var data []byte
    69  
    70  	sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
    71  	sh.Data = ptr
    72  	sh.Len = size
    73  	sh.Cap = size
    74  
    75  	return data
    76  }
    77  
    78  // patch patches the trampoline code to store value for multiboot info address,
    79  // entry point, and boot magic value.
    80  //
    81  // All 3 are determined by pretending they are functions, and finding their PC
    82  // within our own address space.
    83  func patch(trampolineStart uintptr, trampoline []byte, magicVal, infoAddr, entryPoint uintptr) ([]byte, error) {
    84  	replace := func(start uintptr, d []byte, f func(), val uint32) error {
    85  		buf := make([]byte, 4)
    86  		ubinary.NativeEndian.PutUint32(buf, val)
    87  
    88  		offset := funcPC(f) - start
    89  		if int(offset+4) > len(d) {
    90  			return io.ErrUnexpectedEOF
    91  		}
    92  		copy(d[int(offset):], buf)
    93  		return nil
    94  	}
    95  
    96  	if err := replace(trampolineStart, trampoline, info, uint32(infoAddr)); err != nil {
    97  		return nil, err
    98  	}
    99  	if err := replace(trampolineStart, trampoline, entry, uint32(entryPoint)); err != nil {
   100  		return nil, err
   101  	}
   102  	if err := replace(trampolineStart, trampoline, magic, uint32(magicVal)); err != nil {
   103  		return nil, err
   104  	}
   105  	return trampoline, nil
   106  }