github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/kexec/kexec_linux.go (about) 1 // Copyright 2015-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 // kexec executes a new kernel over the running kernel (u-root). 6 // 7 // Synopsis: 8 // kexec [--initrd=FILE] [--command-line=STRING] [-l] [-e] [KERNELIMAGE] 9 // 10 // Description: 11 // Loads a kernel for later execution. 12 // 13 // Options: 14 // --append string Append to the kernel command line 15 // -c, --cmdline string Append to the kernel command line 16 // -d, --debug Print debug info (default true) 17 // -e, --exec Execute a currently loaded kernel 18 // -x, --extra string Add a cpio containing extra files 19 // --initramfs string Use file as the kernel's initial ramdisk 20 // -i, --initrd string Use file as the kernel's initial ramdisk 21 // -l, --load Load the new kernel into the current kernel 22 // -L, --loadsyscall Use the kexec load syscall (not file_load) (default true) 23 // --module stringArray Load multiboot module with command line args (e.g --module="mod arg1") 24 // -p, --purgatory string pick a purgatory, use '-p xyz' to get a list (default "default") 25 // --reuse-cmdline Use the kernel command line from running system 26 27 package main 28 29 import ( 30 "io" 31 "log" 32 "os" 33 "strings" 34 35 flag "github.com/spf13/pflag" 36 37 "github.com/mvdan/u-root-coreutils/pkg/boot" 38 "github.com/mvdan/u-root-coreutils/pkg/boot/kexec" 39 "github.com/mvdan/u-root-coreutils/pkg/boot/linux" 40 "github.com/mvdan/u-root-coreutils/pkg/boot/multiboot" 41 "github.com/mvdan/u-root-coreutils/pkg/boot/purgatory" 42 "github.com/mvdan/u-root-coreutils/pkg/cmdline" 43 "github.com/mvdan/u-root-coreutils/pkg/uio" 44 ) 45 46 type options struct { 47 cmdline string 48 debug bool 49 dtb string 50 exec bool 51 extra string 52 initramfs string 53 load bool 54 loadSyscall bool 55 mmapInitrd bool 56 mmapKernel bool 57 modules []string 58 purgatory string 59 reuseCmdline bool 60 } 61 62 func registerFlags() *options { 63 o := &options{} 64 flag.StringVarP(&o.cmdline, "cmdline", "c", "", "Append to the kernel command line") 65 flag.StringVar(&o.cmdline, "append", "", "Append to the kernel command line") 66 flag.BoolVarP(&o.debug, "debug", "d", false, "Print debug info") 67 flag.StringVar(&o.dtb, "dtb", "", "FILE used as the flatten device tree blob") 68 flag.BoolVarP(&o.exec, "exec", "e", false, "Execute a currently loaded kernel") 69 flag.StringVarP(&o.extra, "extra", "x", "", "Add a cpio containing extra files") 70 flag.StringVarP(&o.initramfs, "initrd", "i", "", "Use file as the kernel's initial ramdisk") 71 flag.StringVar(&o.initramfs, "initramfs", "", "Use file as the kernel's initial ramdisk") 72 flag.BoolVarP(&o.load, "load", "l", false, "Load the new kernel into the current kernel") 73 flag.BoolVarP(&o.loadSyscall, "loadsyscall", "L", false, "Use the kexec_load syscall (not kexec_file_load)") 74 flag.BoolVar(&o.mmapInitrd, "mmap-initrd", true, "Mmap initrd file into virtual buffer, other than directly reading it (Only supported in Arm64 classic load mode for now)") 75 flag.BoolVar(&o.mmapKernel, "mmap-kernel", true, "Mmap kernel file into virtual buffer, other than directly reading it (Only supported in Arm64 classi load mode for now)") 76 flag.StringArrayVar(&o.modules, "module", nil, `Load multiboot module with command line args (e.g --module="mod arg1")`) 77 78 // This is broken out as it is almost never to be used. But it is valueable, nonetheless. 79 flag.StringVarP(&o.purgatory, "purgatory", "p", "default", "picks a purgatory only if loading a Linux kernel with kexec_load, use '-p xyz' to get a list") 80 flag.BoolVar(&o.reuseCmdline, "reuse-cmdline", false, "Use the kernel command line from running system") 81 return o 82 } 83 84 func main() { 85 opts := registerFlags() 86 flag.Parse() 87 88 if opts.debug { 89 linux.Debug = log.Printf 90 purgatory.Debug = log.Printf 91 } 92 93 if (!opts.exec && flag.NArg() == 0) || flag.NArg() > 1 { 94 flag.PrintDefaults() 95 log.Fatalf("usage: kexec [flags] kernelname OR kexec -e") 96 } 97 98 if opts.cmdline != "" && opts.reuseCmdline { 99 flag.PrintDefaults() 100 log.Fatalf("--reuse-cmdline and other command line options are mutually exclusive") 101 } 102 103 if !opts.load && !opts.exec { 104 opts.load = true 105 opts.exec = true 106 } 107 108 newCmdline := opts.cmdline 109 if opts.reuseCmdline { 110 procCmdLine := cmdline.NewCmdLine() 111 if procCmdLine.Err != nil { 112 log.Fatal("Couldn't read /proc/cmdline") 113 } else { 114 newCmdline = procCmdLine.Raw 115 } 116 } 117 118 if err := purgatory.Select(opts.purgatory); err != nil { 119 log.Fatal(err) 120 } 121 if opts.load { 122 kernelpath := flag.Arg(0) 123 kernel, err := os.Open(kernelpath) 124 if err != nil { 125 log.Fatal(err) 126 } 127 defer kernel.Close() 128 var image boot.OSImage 129 if err := multiboot.Probe(kernel); err == nil { 130 image = &boot.MultibootImage{ 131 Modules: multiboot.LazyOpenModules(opts.modules), 132 Kernel: kernel, 133 Cmdline: newCmdline, 134 } 135 } else { 136 var files []io.ReaderAt 137 if len(opts.extra) > 0 { 138 initrd, err := boot.CreateInitrd(strings.Fields(opts.extra)...) 139 if err != nil { 140 log.Fatal(err) 141 } 142 files = append(files, initrd) 143 } 144 if opts.initramfs != "" { 145 for _, n := range strings.Fields(opts.initramfs) { 146 files = append(files, uio.NewLazyFile(n)) 147 } 148 } 149 var i io.ReaderAt 150 if len(files) > 0 { 151 i = boot.CatInitrds(files...) 152 } 153 154 var dtb io.ReaderAt 155 if len(opts.dtb) > 0 { 156 dtb, err = os.Open(opts.dtb) 157 if err != nil { 158 log.Fatalf("Failed to open dtb file %s: %v", opts.dtb, err) 159 } 160 } 161 image = &boot.LinuxImage{ 162 Kernel: uio.NewLazyFile(kernelpath), 163 Initrd: i, 164 Cmdline: newCmdline, 165 LoadSyscall: opts.loadSyscall, 166 KexecOpts: linux.KexecOptions{ 167 DTB: dtb, 168 MmapKernel: opts.mmapKernel, 169 MmapRamfs: opts.mmapInitrd, 170 }, 171 } 172 } 173 if err := image.Load(opts.debug); err != nil { 174 log.Fatal(err) 175 } 176 } 177 178 if opts.exec { 179 if err := kexec.Reboot(); err != nil { 180 log.Fatalf("%v", err) 181 } 182 } 183 }