mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 17:26:28 +00:00
Merge pull request #2355 from justincormack/bootrom
Support UEFI ISO boot on hyperkit
This commit is contained in:
commit
d7caf92708
@ -12,9 +12,8 @@ Alternatively, you can install HyperKit and VPNKit standalone and use it without
|
|||||||
|
|
||||||
## Boot
|
## Boot
|
||||||
|
|
||||||
The HyperKit backend currently only supports booting the
|
The HyperKit backend currently supports booting the
|
||||||
`kernel+initrd` output from `moby` (technically we could support EFI
|
`kernel+initrd` output from `moby`, and EFI ISOs using the EFI firmware.
|
||||||
boot as well).
|
|
||||||
|
|
||||||
|
|
||||||
## Console
|
## Console
|
||||||
@ -28,8 +27,8 @@ HyperKit does not provide a console device.
|
|||||||
## Disks
|
## Disks
|
||||||
|
|
||||||
The HyperKit backend support configuring a persistent disk using the
|
The HyperKit backend support configuring a persistent disk using the
|
||||||
standard `linuxkit` `-disk` syntax. Currently, only one disk is
|
standard `linuxkit` `-disk` syntax. Multiple disks are
|
||||||
supported and the disk is in raw format.
|
supported and the disks are in raw format.
|
||||||
|
|
||||||
## Power management
|
## Power management
|
||||||
|
|
||||||
@ -128,8 +127,8 @@ there are a number of packages, such as `vsudd`, which enable
|
|||||||
tighter integration of the VM with the host (see below).
|
tighter integration of the VM with the host (see below).
|
||||||
|
|
||||||
The HyperKit backend also allows passing custom userdata into the
|
The HyperKit backend also allows passing custom userdata into the
|
||||||
[metadata pacakge](./metadata.md) using the `-data` command-line
|
[metadata package](./metadata.md) using the `-data` command-line
|
||||||
option.
|
option. This attaches a CD device with the data on.
|
||||||
|
|
||||||
|
|
||||||
### `vsudd` unix domain socket forwarding
|
### `vsudd` unix domain socket forwarding
|
||||||
|
@ -46,6 +46,15 @@ func runHyperKit(args []string) {
|
|||||||
vsockports := flags.String("vsock-ports", "", "List of vsock ports to forward from the guest on startup (comma separated). A unix domain socket for each port will be created in the state directory")
|
vsockports := flags.String("vsock-ports", "", "List of vsock ports to forward from the guest on startup (comma separated). A unix domain socket for each port will be created in the state directory")
|
||||||
networking := flags.String("networking", hyperkitNetworkingDefault, "Networking mode. Valid options are 'default', 'docker-for-mac', 'vpnkit[,socket-path]', 'vmnet' and 'none'. 'docker-for-mac' connects to the network used by Docker for Mac. 'vpnkit' connects to the VPNKit socket specified. If socket-path is omitted a new VPNKit instance will be started and 'vpnkit_eth.sock' will be created in the state directory. 'vmnet' uses the Apple vmnet framework, requires root/sudo. 'none' disables networking.`")
|
networking := flags.String("networking", hyperkitNetworkingDefault, "Networking mode. Valid options are 'default', 'docker-for-mac', 'vpnkit[,socket-path]', 'vmnet' and 'none'. 'docker-for-mac' connects to the network used by Docker for Mac. 'vpnkit' connects to the VPNKit socket specified. If socket-path is omitted a new VPNKit instance will be started and 'vpnkit_eth.sock' will be created in the state directory. 'vmnet' uses the Apple vmnet framework, requires root/sudo. 'none' disables networking.`")
|
||||||
|
|
||||||
|
// Boot type; we try to determine automatically
|
||||||
|
uefiBoot := flags.Bool("uefi", false, "Use UEFI boot")
|
||||||
|
isoBoot := flags.Bool("iso", false, "Boot image is an ISO")
|
||||||
|
kernelBoot := flags.Bool("kernel", false, "Boot image is kernel+initrd+cmdline 'path'-kernel/-initrd/-cmdline")
|
||||||
|
|
||||||
|
// Paths and settings for UEFI firware
|
||||||
|
// Note, the default uses the firmware shipped with Docker for Mac
|
||||||
|
fw := flags.String("fw", "/Applications/Docker.app/Contents/Resources/uefi/UEFI.fd", "Path to OVMF firmware for UEFI boot")
|
||||||
|
|
||||||
if err := flags.Parse(args); err != nil {
|
if err := flags.Parse(args); err != nil {
|
||||||
log.Fatal("Unable to parse args")
|
log.Fatal("Unable to parse args")
|
||||||
}
|
}
|
||||||
@ -55,7 +64,50 @@ func runHyperKit(args []string) {
|
|||||||
flags.Usage()
|
flags.Usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
prefix := remArgs[0]
|
path := remArgs[0]
|
||||||
|
prefix := path
|
||||||
|
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
stat := err == nil
|
||||||
|
|
||||||
|
var isoPaths []string
|
||||||
|
|
||||||
|
// if the path does not exist, must be trying to do a kernel boot
|
||||||
|
if !stat {
|
||||||
|
_, err = os.Stat(path + "-kernel")
|
||||||
|
statKernel := err == nil
|
||||||
|
if statKernel {
|
||||||
|
*kernelBoot = true
|
||||||
|
} else {
|
||||||
|
log.Fatalf("Cannot find kernel file (%s): %v", path+"-kernel", err)
|
||||||
|
}
|
||||||
|
_, err = os.Stat(path + "-initrd.img")
|
||||||
|
statInitrd := err == nil
|
||||||
|
if !statInitrd {
|
||||||
|
log.Fatalf("Cannot find initrd file (%s): %v", path+"-initrd.img", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if path ends in .iso they meant an ISO
|
||||||
|
if strings.HasSuffix(path, ".iso") {
|
||||||
|
*isoBoot = true
|
||||||
|
prefix = strings.TrimSuffix(path, ".iso")
|
||||||
|
// hyperkit only supports UEFI ISO boot at present
|
||||||
|
if !*uefiBoot {
|
||||||
|
log.Fatalf("Hyperkit requires --uefi to be set to boot an ISO")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if *isoBoot {
|
||||||
|
isoPaths = append(isoPaths, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *uefiBoot {
|
||||||
|
_, err := os.Stat(*fw)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot open UEFI firmware file (%s): %v", *fw, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if *state == "" {
|
if *state == "" {
|
||||||
*state = prefix + "-state"
|
*state = prefix + "-state"
|
||||||
@ -64,7 +116,6 @@ func runHyperKit(args []string) {
|
|||||||
log.Fatalf("Could not create state directory: %v", err)
|
log.Fatalf("Could not create state directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
isoPath := ""
|
|
||||||
if *data != "" {
|
if *data != "" {
|
||||||
var d []byte
|
var d []byte
|
||||||
if _, err := os.Stat(*data); os.IsNotExist(err) {
|
if _, err := os.Stat(*data); os.IsNotExist(err) {
|
||||||
@ -75,10 +126,11 @@ func runHyperKit(args []string) {
|
|||||||
log.Fatalf("Cannot read user data: %v", err)
|
log.Fatalf("Cannot read user data: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isoPath = filepath.Join(*state, "data.iso")
|
isoPath := filepath.Join(*state, "data.iso")
|
||||||
if err := WriteMetadataISO(isoPath, d); err != nil {
|
if err := WriteMetadataISO(isoPath, d); err != nil {
|
||||||
log.Fatalf("Cannot write user data ISO: %v", err)
|
log.Fatalf("Cannot write user data ISO: %v", err)
|
||||||
}
|
}
|
||||||
|
isoPaths = append(isoPaths, isoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
vpnKitKey := ""
|
vpnKitKey := ""
|
||||||
@ -99,9 +151,12 @@ func runHyperKit(args []string) {
|
|||||||
vmUUID := uuid.NewV4().String()
|
vmUUID := uuid.NewV4().String()
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
cmdline, err := ioutil.ReadFile(prefix + "-cmdline")
|
var cmdline []byte
|
||||||
if err != nil {
|
if *kernelBoot {
|
||||||
log.Fatalf("Cannot open cmdline file: %v", err)
|
cmdline, err = ioutil.ReadFile(prefix + "-cmdline")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot open cmdline file: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new HyperKit instance (w/o networking for now)
|
// Create new HyperKit instance (w/o networking for now)
|
||||||
@ -175,11 +230,15 @@ func runHyperKit(args []string) {
|
|||||||
log.Fatalf("Invalid networking mode: %s", netMode[0])
|
log.Fatalf("Invalid networking mode: %s", netMode[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Kernel = prefix + "-kernel"
|
if *kernelBoot {
|
||||||
h.Initrd = prefix + "-initrd.img"
|
h.Kernel = prefix + "-kernel"
|
||||||
|
h.Initrd = prefix + "-initrd.img"
|
||||||
|
} else {
|
||||||
|
h.Bootrom = *fw
|
||||||
|
}
|
||||||
h.VPNKitKey = vpnKitKey
|
h.VPNKitKey = vpnKitKey
|
||||||
h.UUID = vmUUID
|
h.UUID = vmUUID
|
||||||
h.ISOImage = isoPath
|
h.ISOImages = isoPaths
|
||||||
h.VSock = true
|
h.VSock = true
|
||||||
h.CPUs = *cpus
|
h.CPUs = *cpus
|
||||||
h.Memory = *mem
|
h.Memory = *mem
|
||||||
|
@ -174,11 +174,6 @@ func runQemu(args []string) {
|
|||||||
*isoBoot = true
|
*isoBoot = true
|
||||||
prefix = strings.TrimSuffix(path, ".iso")
|
prefix = strings.TrimSuffix(path, ".iso")
|
||||||
}
|
}
|
||||||
// autodetect EFI ISO from our default naming
|
|
||||||
if strings.HasSuffix(path, "-efi.iso") {
|
|
||||||
*uefiBoot = true
|
|
||||||
prefix = strings.TrimSuffix(path, "-efi.iso")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if *state == "" {
|
if *state == "" {
|
||||||
|
@ -12,7 +12,7 @@ github.com/googleapis/gax-go 8c5154c0fe5bf18cf649634d4c6df50897a32751
|
|||||||
github.com/gophercloud/gophercloud 2804b72cf099b41d2e25c8afcca786f9f962ddee
|
github.com/gophercloud/gophercloud 2804b72cf099b41d2e25c8afcca786f9f962ddee
|
||||||
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
|
||||||
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
github.com/mitchellh/go-ps 4fdf99ab29366514c69ccccddab5dc58b8d84062
|
||||||
github.com/moby/hyperkit 2dbe405bfb05a93b2237516d1bffed850a4685f3
|
github.com/moby/hyperkit a82b409a87f12fa3306813410c37f4eed270efac
|
||||||
github.com/packethost/packngo 91d54000aa56874149d348a884ba083c41d38091
|
github.com/packethost/packngo 91d54000aa56874149d348a884ba083c41d38091
|
||||||
github.com/radu-matei/azure-sdk-for-go 3b12823551999669c9a325a32472508e0af7978e
|
github.com/radu-matei/azure-sdk-for-go 3b12823551999669c9a325a32472508e0af7978e
|
||||||
github.com/radu-matei/azure-vhd-utils e52754d5569d2a643a7775f72ff2a6cf524f4c25
|
github.com/radu-matei/azure-vhd-utils e52754d5569d2a643a7775f72ff2a6cf524f4c25
|
||||||
|
2
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/README.md
generated
vendored
2
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/README.md
generated
vendored
@ -38,7 +38,7 @@ via `brew` and using `opam` to install the appropriate libraries:
|
|||||||
$ brew install opam libev
|
$ brew install opam libev
|
||||||
$ opam init
|
$ opam init
|
||||||
$ eval `opam config env`
|
$ eval `opam config env`
|
||||||
$ opam install uri qcow.0.10.0 qcow-tool mirage-block-unix.2.7.0 conf-libev logs fmt mirage-unix prometheus-app
|
$ opam install uri qcow.0.10.3 conduit.1.0.0 lwt.3.1.0 qcow-tool mirage-block-unix.2.7.0 conf-libev logs fmt mirage-unix prometheus-app
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
|
58
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/go/hyperkit.go
generated
vendored
58
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/go/hyperkit.go
generated
vendored
@ -71,8 +71,10 @@ type Socket9P struct {
|
|||||||
|
|
||||||
// DiskConfig contains the path to a disk image and an optional size if the image needs to be created.
|
// DiskConfig contains the path to a disk image and an optional size if the image needs to be created.
|
||||||
type DiskConfig struct {
|
type DiskConfig struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Size int `json:"size"`
|
Size int `json:"size"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
Driver string `json:"driver"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HyperKit contains the configuration of the hyperkit VM
|
// HyperKit contains the configuration of the hyperkit VM
|
||||||
@ -90,7 +92,7 @@ type HyperKit struct {
|
|||||||
// Disks contains disk images to use/create.
|
// Disks contains disk images to use/create.
|
||||||
Disks []DiskConfig `json:"disks"`
|
Disks []DiskConfig `json:"disks"`
|
||||||
// ISOImage is the (optional) path to a ISO image to attach
|
// ISOImage is the (optional) path to a ISO image to attach
|
||||||
ISOImage string `json:"iso"`
|
ISOImages []string `json:"iso"`
|
||||||
// VSock enables the virtio-socket device and exposes it on the host
|
// VSock enables the virtio-socket device and exposes it on the host
|
||||||
VSock bool `json:"vsock"`
|
VSock bool `json:"vsock"`
|
||||||
// VSockPorts is a list of guest VSock ports that should be exposed as sockets on the host
|
// VSockPorts is a list of guest VSock ports that should be exposed as sockets on the host
|
||||||
@ -108,6 +110,8 @@ type HyperKit struct {
|
|||||||
Kernel string `json:"kernel"`
|
Kernel string `json:"kernel"`
|
||||||
// Initrd is the path to the initial ramdisk to boot off
|
// Initrd is the path to the initial ramdisk to boot off
|
||||||
Initrd string `json:"initrd"`
|
Initrd string `json:"initrd"`
|
||||||
|
// Bootrom is the path to a boot rom eg for UEFI boot
|
||||||
|
Bootrom string `json:"bootrom"`
|
||||||
|
|
||||||
// CPUs is the number CPUs to configure
|
// CPUs is the number CPUs to configure
|
||||||
CPUs int `json:"cpus"`
|
CPUs int `json:"cpus"`
|
||||||
@ -222,9 +226,9 @@ func (h *HyperKit) execute(cmdline string) error {
|
|||||||
if h.Console == ConsoleStdio && !isTerminal(os.Stdout) && h.StateDir == "" {
|
if h.Console == ConsoleStdio && !isTerminal(os.Stdout) && h.StateDir == "" {
|
||||||
return fmt.Errorf("If ConsoleStdio is set but stdio is not a terminal, StateDir must be specified")
|
return fmt.Errorf("If ConsoleStdio is set but stdio is not a terminal, StateDir must be specified")
|
||||||
}
|
}
|
||||||
if h.ISOImage != "" {
|
for _, image := range h.ISOImages {
|
||||||
if _, err = os.Stat(h.ISOImage); os.IsNotExist(err) {
|
if _, err = os.Stat(image); os.IsNotExist(err) {
|
||||||
return fmt.Errorf("ISO %s does not exist", h.ISOImage)
|
return fmt.Errorf("ISO %s does not exist", image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h.VSock && h.StateDir == "" {
|
if h.VSock && h.StateDir == "" {
|
||||||
@ -233,11 +237,17 @@ func (h *HyperKit) execute(cmdline string) error {
|
|||||||
if !h.VSock && len(h.VSockPorts) > 0 {
|
if !h.VSock && len(h.VSockPorts) > 0 {
|
||||||
return fmt.Errorf("To forward vsock ports vsock must be enabled")
|
return fmt.Errorf("To forward vsock ports vsock must be enabled")
|
||||||
}
|
}
|
||||||
if _, err = os.Stat(h.Kernel); os.IsNotExist(err) {
|
if h.Bootrom == "" {
|
||||||
return fmt.Errorf("Kernel %s does not exist", h.Kernel)
|
if _, err = os.Stat(h.Kernel); os.IsNotExist(err) {
|
||||||
}
|
return fmt.Errorf("Kernel %s does not exist", h.Kernel)
|
||||||
if _, err = os.Stat(h.Initrd); os.IsNotExist(err) {
|
}
|
||||||
return fmt.Errorf("initrd %s does not exist", h.Initrd)
|
if _, err = os.Stat(h.Initrd); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("initrd %s does not exist", h.Initrd)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err = os.Stat(h.Bootrom); os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("Bootrom %s does not exist", h.Bootrom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create files
|
// Create files
|
||||||
@ -428,7 +438,18 @@ func (h *HyperKit) buildArgs(cmdline string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range h.Disks {
|
for _, p := range h.Disks {
|
||||||
a = append(a, "-s", fmt.Sprintf("%d:0,virtio-blk,%s", nextSlot, p.Path))
|
// Default the driver to virtio-blk
|
||||||
|
driver := "virtio-blk"
|
||||||
|
if p.Driver != "" {
|
||||||
|
driver = p.Driver
|
||||||
|
}
|
||||||
|
arg := fmt.Sprintf("%d:0,%s,%s", nextSlot, driver, p.Path)
|
||||||
|
|
||||||
|
// Add on a format instruction if specified.
|
||||||
|
if p.Format != "" {
|
||||||
|
arg += ",format=" + p.Format
|
||||||
|
}
|
||||||
|
a = append(a, "-s", arg)
|
||||||
nextSlot++
|
nextSlot++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,8 +462,8 @@ func (h *HyperKit) buildArgs(cmdline string) {
|
|||||||
nextSlot++
|
nextSlot++
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.ISOImage != "" {
|
for _, image := range h.ISOImages {
|
||||||
a = append(a, "-s", fmt.Sprintf("%d,ahci-cd,%s", nextSlot, h.ISOImage))
|
a = append(a, "-s", fmt.Sprintf("%d,ahci-cd,%s", nextSlot, image))
|
||||||
nextSlot++
|
nextSlot++
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +481,13 @@ func (h *HyperKit) buildArgs(cmdline string) {
|
|||||||
a = append(a, "-l", fmt.Sprintf("com1,autopty=%s/tty,log=%s/console-ring", h.StateDir, h.StateDir))
|
a = append(a, "-l", fmt.Sprintf("com1,autopty=%s/tty,log=%s/console-ring", h.StateDir, h.StateDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
kernArgs := fmt.Sprintf("kexec,%s,%s,earlyprintk=serial %s", h.Kernel, h.Initrd, cmdline)
|
if h.Bootrom == "" {
|
||||||
a = append(a, "-f", kernArgs)
|
kernArgs := fmt.Sprintf("kexec,%s,%s,earlyprintk=serial %s", h.Kernel, h.Initrd, cmdline)
|
||||||
|
a = append(a, "-f", kernArgs)
|
||||||
|
} else {
|
||||||
|
kernArgs := fmt.Sprintf("bootrom,%s,,", h.Bootrom)
|
||||||
|
a = append(a, "-f", kernArgs)
|
||||||
|
}
|
||||||
|
|
||||||
h.Arguments = a
|
h.Arguments = a
|
||||||
h.CmdLine = h.HyperKit + " " + strings.Join(a, " ")
|
h.CmdLine = h.HyperKit + " " + strings.Join(a, " ")
|
||||||
|
2
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/src/include/xhyve/virtio.h
generated
vendored
2
src/cmd/linuxkit/vendor/github.com/moby/hyperkit/src/include/xhyve/virtio.h
generated
vendored
@ -212,7 +212,7 @@ struct vring_used {
|
|||||||
#define VIRTIO_VENDOR 0x1AF4
|
#define VIRTIO_VENDOR 0x1AF4
|
||||||
#define VIRTIO_DEV_NET 0x1000
|
#define VIRTIO_DEV_NET 0x1000
|
||||||
#define VIRTIO_DEV_BLOCK 0x1001
|
#define VIRTIO_DEV_BLOCK 0x1001
|
||||||
#define VIRTIO_DEV_RANDOM 0x1002
|
#define VIRTIO_DEV_RANDOM 0x1005
|
||||||
#define VIRTIO_DEV_9P 0x1009
|
#define VIRTIO_DEV_9P 0x1009
|
||||||
#define VIRTIO_DEV_SOCK 0x103f /* In the legacy range. */
|
#define VIRTIO_DEV_SOCK 0x103f /* In the legacy range. */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user