gokrazy/reboot_amd64.go
Michael Stapelberg 4f0e427025 reboot: use kexec where possible
This doesn’t work on the Raspberry Pi yet (due to missing kexec_file_load), but
I tested it in qemu.
2018-06-17 09:29:29 +02:00

66 lines
1.5 KiB
Go

package gokrazy
import (
"io/ioutil"
"log"
"os"
"path/filepath"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
)
// TODO: get these constants into sys/unix
const (
KEXEC_ARCH_DEFAULT = (0 << 16)
KEXEC_FILE_NO_INITRAMFS = 0x00000004
)
func kexecReboot() error {
tmpdir, err := ioutil.TempDir("", "kexec")
if err != nil {
return err
}
if err := syscall.Mount(mustFindRootDevice()+"1", tmpdir, "vfat", 0, ""); err != nil {
return err
}
kernel, err := os.Open(filepath.Join(tmpdir, "vmlinuz"))
if err != nil {
return err
}
defer kernel.Close()
cmdline, err := ioutil.ReadFile("/proc/cmdline")
if err != nil {
return err
}
rep := rootRe.ReplaceAllLiteral(cmdline, []byte("root="+mustFindRootDevice()+inactiveRootPartition))
// NUL-terminate cmdline
cmdlinebuf := make([]byte, len(rep)+1)
copy(cmdlinebuf, rep)
_, _, errno := unix.Syscall6(
unix.SYS_KEXEC_FILE_LOAD,
uintptr(kernel.Fd()), // kernel_fd
0, // initrd_fd
uintptr(len(cmdline)+1), // cmdline_len
uintptr(unsafe.Pointer(&cmdlinebuf[0])), // cmdline
KEXEC_ARCH_DEFAULT|KEXEC_FILE_NO_INITRAMFS, // flags
0)
if errno != 0 {
// errno is syscall.ENOSYS on kernels without CONFIG_KEXEC_FILE_LOAD=y
return errno
}
return unix.Reboot(unix.LINUX_REBOOT_CMD_KEXEC)
}
func reboot() error {
if err := kexecReboot(); err != nil {
log.Printf("kexec reboot failed: %v", err)
return unix.Reboot(unix.LINUX_REBOOT_CMD_RESTART)
}
return nil
}