7
"github.com/crc-org/vfkit/pkg/util"
10
// Bootloader is the base interface for all bootloader classes. It specifies how to
11
// boot the virtual machine. It is mandatory to set a Bootloader or the virtual
12
// machine won't start.
13
type Bootloader interface {
14
FromOptions(options []option) error
15
ToCmdLine() ([]string, error)
18
// LinuxBootloader determines which kernel/initrd/kernel args to use when starting
19
// the virtual machine.
20
type LinuxBootloader struct {
26
// EFIBootloader allows to set a few options related to EFI variable storage
27
type EFIBootloader struct {
28
EFIVariableStorePath string
29
// TODO: virtualization framework allow both create and overwrite
30
CreateVariableStore bool
33
// NewLinuxBootloader creates a new bootloader to start a VM with the file at
34
// vmlinuzPath as the kernel, kernelCmdLine as the kernel command line, and the
35
// file at initrdPath as the initrd. On ARM64, the kernel must be uncompressed
36
// otherwise the VM will fail to boot.
37
func NewLinuxBootloader(vmlinuzPath, kernelCmdLine, initrdPath string) *LinuxBootloader {
38
return &LinuxBootloader{
39
VmlinuzPath: vmlinuzPath,
40
KernelCmdLine: kernelCmdLine,
41
InitrdPath: initrdPath,
45
func (bootloader *LinuxBootloader) FromOptions(options []option) error {
46
for _, option := range options {
49
bootloader.VmlinuzPath = option.value
51
bootloader.KernelCmdLine = util.TrimQuotes(option.value)
53
bootloader.InitrdPath = option.value
55
return fmt.Errorf("unknown option for linux bootloaders: %s", option.key)
61
func (bootloader *LinuxBootloader) ToCmdLine() ([]string, error) {
63
if bootloader.VmlinuzPath == "" {
64
return nil, fmt.Errorf("missing kernel path")
66
args = append(args, "--kernel", bootloader.VmlinuzPath)
68
if bootloader.InitrdPath == "" {
69
return nil, fmt.Errorf("missing initrd path")
71
args = append(args, "--initrd", bootloader.InitrdPath)
73
if bootloader.KernelCmdLine == "" {
74
return nil, fmt.Errorf("missing kernel command line")
76
args = append(args, "--kernel-cmdline", bootloader.KernelCmdLine)
81
// NewEFIBootloader creates a new bootloader to start a VM using EFI
82
// efiVariableStorePath is the path to a file for EFI storage
83
// create is a boolean indicating if the file for the store should be created or not
84
func NewEFIBootloader(efiVariableStorePath string, createVariableStore bool) *EFIBootloader {
85
return &EFIBootloader{
86
EFIVariableStorePath: efiVariableStorePath,
87
CreateVariableStore: createVariableStore,
91
func (bootloader *EFIBootloader) FromOptions(options []option) error {
92
for _, option := range options {
94
case "variable-store":
95
bootloader.EFIVariableStorePath = option.value
97
if option.value != "" {
98
return fmt.Errorf("unexpected value for EFI bootloader 'create' option: %s", option.value)
100
bootloader.CreateVariableStore = true
102
return fmt.Errorf("unknown option for EFI bootloaders: %s", option.key)
108
func (bootloader *EFIBootloader) ToCmdLine() ([]string, error) {
109
if bootloader.EFIVariableStorePath == "" {
110
return nil, fmt.Errorf("missing EFI store path")
113
builder := strings.Builder{}
114
builder.WriteString("efi")
115
builder.WriteString(fmt.Sprintf(",variable-store=%s", bootloader.EFIVariableStorePath))
116
if bootloader.CreateVariableStore {
117
builder.WriteString(",create")
120
return []string{"--bootloader", builder.String()}, nil
123
func BootloaderFromCmdLine(optsStrv []string) (Bootloader, error) {
124
var bootloader Bootloader
126
if len(optsStrv) < 1 {
127
return nil, fmt.Errorf("empty option list in --bootloader command line argument")
129
bootloaderType := optsStrv[0]
130
switch bootloaderType {
132
bootloader = &EFIBootloader{}
134
bootloader = &LinuxBootloader{}
136
return nil, fmt.Errorf("unknown bootloader type: %s", bootloaderType)
138
options := strvToOptions(optsStrv[1:])
139
if err := bootloader.FromOptions(options); err != nil {
142
return bootloader, nil