+my $boot_fmt = {
+ legacy => {
+ optional => 1,
+ default_key => 1,
+ type => 'string',
+ description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
+ . " Deprecated, use 'order=' instead.",
+ pattern => '[acdn]{1,4}',
+ format_description => "[acdn]{1,4}",
+
+ # note: this is also the fallback if boot: is not given at all
+ default => 'cdn',
+ },
+ order => {
+ optional => 1,
+ type => 'string',
+ format => 'pve-qm-bootdev-list',
+ format_description => "device[;device...]",
+ description => <<EODESC,
+The guest will attempt to boot from devices in the order they appear here.
+
+Disks, optical drives and passed-through storage USB devices will be directly
+booted from, NICs will load PXE, and PCIe devices will either behave like disks
+(e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
+
+Note that only devices in this list will be marked as bootable and thus loaded
+by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
+(e.g. software-raid), you need to specify all of them here.
+
+Overrides the deprecated 'legacy=[acdn]*' value when given.
+EODESC
+ },
+};
+PVE::JSONSchema::register_format('pve-qm-boot', $boot_fmt);
+
+PVE::JSONSchema::register_format('pve-qm-bootdev', \&verify_bootdev);
+sub verify_bootdev {
+ my ($dev, $noerr) = @_;
+
+ return $dev if PVE::QemuServer::Drive::is_valid_drivename($dev) && $dev !~ m/^efidisk/;
+
+ my $check = sub {
+ my ($base) = @_;
+ return 0 if $dev !~ m/^$base\d+$/;
+ return 0 if !$confdesc->{$dev};
+ return 1;
+ };
+
+ return $dev if $check->("net");
+ return $dev if $check->("usb");
+ return $dev if $check->("hostpci");
+
+ return undef if $noerr;
+ die "invalid boot device '$dev'\n";
+}
+
+sub print_bootorder {
+ my ($devs) = @_;
+ my $data = { order => join(';', @$devs) };
+ return PVE::JSONSchema::print_property_string($data, $boot_fmt);
+}
+