github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/kexec/kexec_load_linux.go (about)

     1  // Copyright 2015-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 kexec
     6  
     7  import (
     8  	"fmt"
     9  	"syscall"
    10  	"unsafe"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  // Load loads the given segments into memory to be executed on a kexec-reboot.
    16  //
    17  // It is assumed that segments is made up of the next kernel's code and text
    18  // segments, and that `entry` is the entry point, either kernel entry point or trampoline.
    19  //
    20  // Load will align segments to page boundaries and deduplicate overlapping ranges.
    21  func Load(entry uintptr, segments Segments, flags uint64) error {
    22  	for i := range segments {
    23  		segments[i] = AlignPhys(segments[i])
    24  	}
    25  
    26  	segments = Dedup(segments)
    27  	if !segments.PhysContains(entry) {
    28  		return fmt.Errorf("entry point %#v is not covered by any segment", entry)
    29  	}
    30  
    31  	return rawLoad(entry, segments, flags)
    32  }
    33  
    34  // ErrKexec is returned by Load if the kexec failed. It describes entry point,
    35  // flags, errno and kernel layout.
    36  type ErrKexec struct {
    37  	Entry    uintptr
    38  	Segments []Segment
    39  	Flags    uint64
    40  	Errno    syscall.Errno
    41  }
    42  
    43  // Error implements error.
    44  func (e ErrKexec) Error() string {
    45  	return fmt.Sprintf("kexec_load(entry=%#x, segments=%s, flags %#x) = errno %s", e.Entry, e.Segments, e.Flags, e.Errno)
    46  }
    47  
    48  // rawLoad is a wrapper around kexec_load(2) syscall.
    49  // Preconditions:
    50  // - segments must not overlap
    51  // - segments must be full pages
    52  func rawLoad(entry uintptr, segments []Segment, flags uint64) error {
    53  	if _, _, errno := unix.Syscall6(
    54  		unix.SYS_KEXEC_LOAD,
    55  		entry,
    56  		uintptr(len(segments)),
    57  		uintptr(unsafe.Pointer(&segments[0])),
    58  		uintptr(flags),
    59  		0, 0); errno != 0 {
    60  		return ErrKexec{
    61  			Entry:    entry,
    62  			Segments: segments,
    63  			Flags:    flags,
    64  			Errno:    errno,
    65  		}
    66  	}
    67  	return nil
    68  }