I want to be able to build vmd images more or less automatically.
This is why I added 'vmctl wait' and this here is the next step.
It allows to boot bsd.rd and pass the needed info to the kernel that the
system thinks it was PXE booted and so the installer will start an
auto_install automatically.

In short you can do now:
    vmctl create disk.img -s 10G
    vmctl start "installer" -Lc -B net -b ./bsd.rd -d disk.img

This will boot the installer which will then fetch install.conf from your
host. For this to work I adjusted the DHCP code to pass a bootfile of
auto_install in the lease (currently hardcoded). After that it is just a
regular network autoinstall

I decided to add a -B flag which could be extended to include things like
net, disk, cdrom and is therefor similar to qemu -boot option. Ideally vmd
would pass this flag also to SeaBIOS (I left this out for somebody else to
tackle). Especially once SeaBIOS support PXE booting it would be nice to
use this flag to flip the boot mode of the BIOS.

-- 
:wq Claudio

Index: vmctl/main.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/main.c,v
retrieving revision 1.49
diff -u -p -r1.49 main.c
--- vmctl/main.c        4 Dec 2018 08:17:17 -0000       1.49
+++ vmctl/main.c        4 Dec 2018 12:04:45 -0000
@@ -79,7 +79,7 @@ struct ctl_command ctl_commands[] = {
        { "reset",      CMD_RESET,      ctl_reset,      "[all|vms|switches]" },
        { "show",       CMD_STATUS,     ctl_status,     "[id]" },
        { "start",      CMD_START,      ctl_start,      "\"name\""
-           " [-Lc] [-b image] [-r image] [-m size]\n"
+           " [-Lc] [-b image] [-B device] [-r image] [-m size]\n"
            "\t\t[-n switch] [-i count] [-d disk]* [-t name]" },
        { "status",     CMD_STATUS,     ctl_status,     "[id]" },
        { "stop",       CMD_STOP,       ctl_stop,       "[id|-a] [-fw]" },
@@ -224,7 +224,7 @@ vmmaction(struct parse_result *res)
        case CMD_START:
                ret = vm_start(res->id, res->name, res->size, res->nifs,
                    res->nets, res->ndisks, res->disks, res->disktypes,
-                   res->path, res->isopath, res->instance);
+                   res->path, res->isopath, res->instance, res->bootdevice);
                if (ret) {
                        errno = ret;
                        err(1, "start VM operation failed");
@@ -843,7 +843,7 @@ ctl_start(struct parse_result *res, int 
        argc--;
        argv++;
 
-       while ((ch = getopt(argc, argv, "b:r:cLm:n:d:i:t:")) != -1) {
+       while ((ch = getopt(argc, argv, "b:B:cd:i:Lm:n:r:t:")) != -1) {
                switch (ch) {
                case 'b':
                        if (res->path)
@@ -852,6 +852,12 @@ ctl_start(struct parse_result *res, int 
                                err(1, "invalid boot image path");
                        if ((res->path = strdup(path)) == NULL)
                                errx(1, "strdup");
+                       break;
+               case 'B':
+                       if (res->bootdevice)
+                               errx(1, "boot device specified multiple times");
+                       if (strcmp("net", optarg) == 0)
+                               res->bootdevice = VMBOOTDEV_NET;
                        break;
                case 'r':
                        if (res->isopath)
Index: vmctl/vmctl.8
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.8,v
retrieving revision 1.55
diff -u -p -r1.55 vmctl.8
--- vmctl/vmctl.8       4 Dec 2018 08:17:17 -0000       1.55
+++ vmctl/vmctl.8       4 Dec 2018 12:04:45 -0000
@@ -143,6 +143,7 @@ command.
 .It Xo Cm start Ar name
 .Op Fl cL
 .Op Fl b Ar path
+.Op Fl B Ar device
 .Op Fl d Ar disk
 .Op Fl i Ar count
 .Op Fl m Ar size
@@ -158,6 +159,15 @@ Starts a VM defined by the specified nam
 Boot the VM with the specified kernel or BIOS image.
 If not specified, the default is to boot using the BIOS image in
 .Pa /etc/firmware/vmm-bios .
+.It Fl B Ar device
+Force system to boot from the specified device for the next boot.
+.Ar device
+can be set to
+.Ar net
+to perform a PXE boot using the first network interface.
+Currently only supported when starting the VM with
+.Fl b 
+specifying a kernel image.
 .It Fl c
 Automatically connect to the VM console.
 .It Fl d Ar disk
Index: vmctl/vmctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.c,v
retrieving revision 1.64
diff -u -p -r1.64 vmctl.c
--- vmctl/vmctl.c       4 Dec 2018 08:17:17 -0000       1.64
+++ vmctl/vmctl.c       4 Dec 2018 12:04:45 -0000
@@ -73,7 +73,7 @@ unsigned int info_flags;
 int
 vm_start(uint32_t start_id, const char *name, int memsize, int nnics,
     char **nics, int ndisks, char **disks, int *disktypes, char *kernel,
-    char *iso, char *instance)
+    char *iso, char *instance, unsigned int bootdevice)
 {
        struct vmop_create_params *vmc;
        struct vm_create_params *vcp;
@@ -184,6 +184,7 @@ vm_start(uint32_t start_id, const char *
                if (strlcpy(vmc->vmc_instance, instance,
                    sizeof(vmc->vmc_instance)) >= sizeof(vmc->vmc_instance))
                        errx(1, "instance vm name too long");
+       vmc->vmc_bootdevice = bootdevice;
 
        imsg_compose(ibuf, IMSG_VMDOP_START_VM_REQUEST, 0, 0, -1,
            vmc, sizeof(struct vmop_create_params));
Index: vmctl/vmctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmctl/vmctl.h,v
retrieving revision 1.29
diff -u -p -r1.29 vmctl.h
--- vmctl/vmctl.h       4 Dec 2018 08:17:17 -0000       1.29
+++ vmctl/vmctl.h       4 Dec 2018 12:04:45 -0000
@@ -59,6 +59,7 @@ struct parse_result {
        char                    *instance;
        unsigned int             flags;
        unsigned int             mode;
+       unsigned int             bootdevice;
        struct ctl_command      *ctl;
 };
 
@@ -93,7 +94,7 @@ int    create_imagefile(int, const char *,
 int     create_raw_imagefile(const char *, long);
 int     create_qc2_imagefile(const char *, const char *, long);
 int     vm_start(uint32_t, const char *, int, int, char **, int,
-           char **, int *, char *, char *, char *);
+           char **, int *, char *, char *, char *, unsigned int);
 int     vm_start_complete(struct imsg *, int *, int);
 void    terminate_vm(uint32_t, const char *, unsigned int);
 int     terminate_vm_complete(struct imsg *, int *, unsigned int);
Index: vmd/dhcp.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/dhcp.c,v
retrieving revision 1.6
diff -u -p -r1.6 dhcp.c
--- vmd/dhcp.c  21 Nov 2018 12:31:47 -0000      1.6
+++ vmd/dhcp.c  4 Dec 2018 12:04:45 -0000
@@ -108,6 +108,9 @@ dhcp_request(struct vionet_dev *dev, cha
        resp.hlen = req.hlen;
        resp.xid = req.xid;
 
+       if (dev->pxeboot)
+               strlcpy(resp.file, "auto_install", sizeof resp.file);
+
        if ((client_addr.s_addr =
            vm_priv_addr(&env->vmd_cfg,
            dev->vm_vmid, dev->idx, 1)) == 0)
@@ -118,12 +121,10 @@ dhcp_request(struct vionet_dev *dev, cha
            sizeof(client_addr));
        ss2sin(&pc.pc_dst)->sin_port = htons(CLIENT_PORT);
 
-       if ((server_addr.s_addr =
-           vm_priv_addr(&env->vmd_cfg,
-           dev->vm_vmid, dev->idx, 0)) == 0)
+       if ((server_addr.s_addr = vm_priv_addr(&env->vmd_cfg, dev->vm_vmid,
+           dev->idx, 0)) == 0)
                return (-1);
-       memcpy(&resp.siaddr, &server_addr,
-           sizeof(server_addr));
+       memcpy(&resp.siaddr, &server_addr, sizeof(server_addr));
        memcpy(&ss2sin(&pc.pc_src)->sin_addr, &server_addr,
            sizeof(server_addr));
        ss2sin(&pc.pc_src)->sin_port = htons(SERVER_PORT);
Index: vmd/loadfile.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/loadfile.h,v
retrieving revision 1.10
diff -u -p -r1.10 loadfile.h
--- vmd/loadfile.h      29 Nov 2017 02:46:10 -0000      1.10
+++ vmd/loadfile.h      4 Dec 2018 12:04:45 -0000
@@ -74,7 +74,7 @@
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
 int loadfile_elf(FILE *, struct vm_create_params *,
-    struct vcpu_reg_state *, uint32_t, uint32_t);
+    struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
 size_t mread(FILE *, paddr_t, size_t);
 
Index: vmd/loadfile_elf.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/loadfile_elf.c,v
retrieving revision 1.30
diff -u -p -r1.30 loadfile_elf.c
--- vmd/loadfile_elf.c  17 Jul 2018 13:47:06 -0000      1.30
+++ vmd/loadfile_elf.c  4 Dec 2018 12:04:45 -0000
@@ -122,7 +122,7 @@ static void setsegment(struct mem_segmen
 static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
 static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
 static size_t create_bios_memmap(struct vm_create_params *, bios_memmap_t *);
-static uint32_t push_bootargs(bios_memmap_t *, size_t);
+static uint32_t push_bootargs(bios_memmap_t *, size_t, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
 static void push_gdt(void);
 static void push_pt_32(void);
@@ -286,13 +286,15 @@ push_pt_64(void)
  */
 int
 loadfile_elf(FILE *fp, struct vm_create_params *vcp,
-    struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto)
+    struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
+    unsigned int bootdevice)
 {
        int r, is_i386 = 0;
        uint32_t bootargsz;
        size_t n, stacksize;
        u_long marks[MARK_MAX];
        bios_memmap_t memmap[VMM_MAX_MEM_RANGES + 1];
+       bios_bootmac_t bm, *bootmac = NULL;
 
        if ((r = fread(&hdr, 1, sizeof(hdr), fp)) != sizeof(hdr))
                return 1;
@@ -323,8 +325,12 @@ loadfile_elf(FILE *fp, struct vm_create_
        else
                push_pt_64();
 
+       if (bootdevice & VMBOOTDEV_NET) {
+               bootmac = &bm;
+               memcpy(bootmac, vcp->vcp_macs[0], ETHER_ADDR_LEN);
+       }
        n = create_bios_memmap(vcp, memmap);
-       bootargsz = push_bootargs(memmap, n);
+       bootargsz = push_bootargs(memmap, n, bootmac);
        stacksize = push_stack(bootargsz, marks[MARK_END], bootdev, howto);
 
 #ifdef __i386__
@@ -409,9 +415,9 @@ create_bios_memmap(struct vm_create_para
  *  The size of the bootargs
  */
 static uint32_t
-push_bootargs(bios_memmap_t *memmap, size_t n)
+push_bootargs(bios_memmap_t *memmap, size_t n, bios_bootmac_t *bootmac)
 {
-       uint32_t memmap_sz, consdev_sz, i;
+       uint32_t memmap_sz, consdev_sz, bootmac_sz, i;
        bios_consdev_t consdev;
        uint32_t ba[1024];
 
@@ -433,13 +439,22 @@ push_bootargs(bios_memmap_t *memmap, siz
        ba[i + 1] = consdev_sz;
        ba[i + 2] = consdev_sz;
        memcpy(&ba[i + 3], &consdev, sizeof(bios_consdev_t));
-       i = i + 3 + (sizeof(bios_consdev_t) / 4);
+       i += consdev_sz / sizeof(int);
+
+       if (bootmac) {
+               bootmac_sz = 3 * sizeof(int) + (sizeof(bios_bootmac_t) + 3) & 
~3;
+               ba[i] = 0x7;   /* bootmac */
+               ba[i + 1] = bootmac_sz;
+               ba[i + 2] = bootmac_sz;
+               memcpy(&ba[i + 3], bootmac, sizeof(bios_bootmac_t));
+               i += bootmac_sz / sizeof(int);
+       } 
 
-       ba[i] = 0xFFFFFFFF; /* BOOTARG_END */
+       ba[i++] = 0xFFFFFFFF; /* BOOTARG_END */
 
        write_mem(BOOTARGS_PAGE, ba, PAGE_SIZE);
 
-       return (memmap_sz + consdev_sz);
+       return (i * sizeof(int));
 }
 
 /*
Index: vmd/virtio.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/virtio.c,v
retrieving revision 1.74
diff -u -p -r1.74 virtio.c
--- vmd/virtio.c        26 Nov 2018 10:39:30 -0000      1.74
+++ vmd/virtio.c        4 Dec 2018 12:04:45 -0000
@@ -1940,14 +1940,17 @@ virtio_init(struct vmd_vm *vm, int child
                            vmc->vmc_ifflags[i] & VMIFF_LOCKED ? 1 : 0;
                        vionet[i].local =
                            vmc->vmc_ifflags[i] & VMIFF_LOCAL ? 1 : 0;
+                       if (i == 0 && vmc->vmc_bootdevice & VMBOOTDEV_NET)
+                               vionet[i].pxeboot = 1;
                        vionet[i].idx = i;
                        vionet[i].pci_id = id;
 
-                       log_debug("%s: vm \"%s\" vio%u lladdr %s%s%s",
+                       log_debug("%s: vm \"%s\" vio%u lladdr %s%s%s%s",
                            __func__, vcp->vcp_name, i,
                            ether_ntoa((void *)vionet[i].mac),
                            vionet[i].lockedmac ? ", locked" : "",
-                           vionet[i].local ? ", local" : "");
+                           vionet[i].local ? ", local" : "",
+                           vionet[i].pxeboot ? ", pxeboot" : "");
                }
        }
 
Index: vmd/virtio.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/virtio.h,v
retrieving revision 1.33
diff -u -p -r1.33 virtio.h
--- vmd/virtio.h        26 Nov 2018 10:39:30 -0000      1.33
+++ vmd/virtio.h        4 Dec 2018 12:04:45 -0000
@@ -212,6 +212,7 @@ struct vionet_dev {
        int idx;
        int lockedmac;
        int local;
+       int pxeboot;
 
        uint8_t pci_id;
 };
Index: vmd/vm.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vm.c,v
retrieving revision 1.41
diff -u -p -r1.41 vm.c
--- vmd/vm.c    8 Oct 2018 16:32:01 -0000       1.41
+++ vmd/vm.c    4 Dec 2018 12:04:45 -0000
@@ -335,7 +335,7 @@ start_vm(struct vmd_vm *vm, int fd)
 
                /* Load kernel image */
                ret = loadfile_elf(fp, vcp, &vrs,
-                   vmboot.vbp_bootdev, vmboot.vbp_howto);
+                   vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
                /*
                 * Try BIOS as a fallback (only if it was provided as an image
Index: vmd/vmd.h
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/vmd.h,v
retrieving revision 1.87
diff -u -p -r1.87 vmd.h
--- vmd/vmd.h   4 Dec 2018 08:15:09 -0000       1.87
+++ vmd/vmd.h   4 Dec 2018 12:04:45 -0000
@@ -173,6 +173,11 @@ struct vmop_create_params {
        unsigned int             vmc_checkaccess;
 
        /* userland-only part of the create params */
+       unsigned int             vmc_bootdevice;
+#define VMBOOTDEV_AUTO         0
+#define VMBOOTDEV_DISK         1
+#define VMBOOTDEV_CDROM                2
+#define VMBOOTDEV_NET          3
        unsigned int             vmc_ifflags[VMM_MAX_NICS_PER_VM];
 #define VMIFF_UP               0x01
 #define VMIFF_LOCKED           0x02

Reply via email to