vmm/vmd fails to boot bsd.rd

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

vmm/vmd fails to boot bsd.rd

Josh Rickmar
>Synopsis: vmm/vmd fails to boot bsd.rd
>Category: vmm
>Environment:
        System      : OpenBSD 6.9
        Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
                         [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

        Architecture: OpenBSD.amd64
        Machine     : amd64
>Description:

vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
is able to be booted in this manner.

>How-To-Repeat:

With this vm.conf:

$ cat /etc/vm.conf
switch "vmnat" {
        interface veb0
}
vm "openbsd" {
        memory 1.5G
        disk "/home/jrick/vm/openbsd.qcow2"
        interface { switch "vmnat" }
        owner jrick
        disable

        boot "/bsd.rd"
}
$ vmctl status
   ID   PID VCPUS  MAXMEM  CURMEM     TTY        OWNER    STATE NAME
   1     -     1    1.5G       -       -        jrick  stopped openbsd
$ vmctl start -c openbsd
Connected to /dev/ttyp5 (speed 115200)
(press any key)
[EOT]
$ tail -2 /var/log/daemon                                                      
Mar  8 16:44:12 drifter vmd[61389]: openbsd: started vm 1 successfully, tty /dev/ttyp5
Mar  8 16:44:12 drifter vmd[2049]: openbsd: failed to load kernel or BIOS - exiting: Exec format error

Another method of testing is to start an adhoc vm instance:

# vmctl start -c -b /bsd.rd test-openbsd
vmctl: starting without disks
vmctl: starting without network interfaces
(hangs here, and seems to forever until I open another xterm)
cu: open("/dev/ttyp6"): Interrupted system call
# tail -2 /var/log/daemon
Mar  8 16:47:06 drifter vmd[61389]: test-openbsd: started vm 2 successfully, tty /dev/ttyp6
Mar  8 16:47:06 drifter vmd[22327]: test-openbsd: failed to load kernel or BIOS - exiting: Exec format error

>Fix:
        unknown

dmesg:
OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
    [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 16762552320 (15986MB)
avail mem = 16239161344 (15486MB)
random: good seed from bootblocks
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 3.1 @ 0x986eb000 (62 entries)
bios0: vendor LENOVO version "R0UET78W (1.58 )" date 11/17/2020
bios0: LENOVO 20KUCTO1WW
acpi0 at bios0: ACPI 5.0
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP SSDT SSDT CRAT CDIT SSDT TPM2 UEFI MSDM BATB HPET APIC MCFG SBST WSMT VFCT IVRS FPDT SSDT SSDT SSDT BGRT UEFI SSDT
acpi0: wakeup devices GPP0(S3) GPP1(S3) GPP2(S3) GPP3(S3) GPP4(S3) GPP5(S3) GPP6(S3) GP17(S3) XHC0(S3) XHC1(S3) GP18(S3) LID_(S3) SLPB(S3)
acpitimer0 at acpi0: 3579545 Hz, 32 bits
acpihpet0 at acpi0: 14318180 Hz
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.62 MHz, 17-11-00
cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu0: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu0: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu0: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 8 var ranges, 88 fixed ranges
cpu0: apic clock running at 24MHz
cpu0: mwait min=64, max=64, C-substates=1.1, IBE
cpu1 at mainbus0: apid 1 (application processor)
cpu1: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu1: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu1: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu1: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu1: disabling user TSC (skew=-7084292078)
cpu1: smt 1, core 0, package 0
cpu2 at mainbus0: apid 2 (application processor)
cpu2: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu2: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu2: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu2: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu2: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu2: disabling user TSC (skew=-7084292028)
cpu2: smt 0, core 1, package 0
cpu3 at mainbus0: apid 3 (application processor)
cpu3: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu3: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu3: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu3: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu3: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu3: disabling user TSC (skew=-7084292078)
cpu3: smt 1, core 1, package 0
cpu4 at mainbus0: apid 4 (application processor)
cpu4: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu4: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu4: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu4: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu4: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu4: disabling user TSC (skew=-7084292028)
cpu4: smt 0, core 2, package 0
cpu5 at mainbus0: apid 5 (application processor)
cpu5: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu5: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu5: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu5: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu5: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu5: disabling user TSC (skew=-7084292078)
cpu5: smt 1, core 2, package 0
cpu6 at mainbus0: apid 6 (application processor)
cpu6: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu6: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu6: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu6: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu6: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu6: disabling user TSC (skew=-7084292018)
cpu6: smt 0, core 3, package 0
cpu7 at mainbus0: apid 7 (application processor)
cpu7: AMD Ryzen 5 2500U with Radeon Vega Mobile Gfx, 1996.25 MHz, 17-11-00
cpu7: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,RDSEED,ADX,SMAP,CLFLUSHOPT,SHA,IBPB,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu7: 64KB 64b/line 4-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu7: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu7: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu7: disabling user TSC (skew=-7084292078)
cpu7: smt 1, core 3, package 0
ioapic0 at mainbus0: apid 32 pa 0xfec00000, version 21, 24 pins, can't remap
ioapic1 at mainbus0: apid 33 pa 0xfec01000, version 21, 32 pins, can't remap
acpimcfg0 at acpi0
acpimcfg0: addr 0xf8000000, bus 0-63
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus 1 (GPP0)
acpiprt2 at acpi0: bus 2 (GPP1)
acpiprt3 at acpi0: bus 3 (GPP2)
acpiprt4 at acpi0: bus -1 (GPP3)
acpiprt5 at acpi0: bus -1 (GPP4)
acpiprt6 at acpi0: bus 4 (GPP5)
acpiprt7 at acpi0: bus -1 (GPP6)
acpiprt8 at acpi0: bus 5 (GP17)
acpiprt9 at acpi0: bus 6 (GP18)
acpiec0 at acpi0
acpibtn0 at acpi0: PWRB
acpipci0 at acpi0 PCI0: 0x00000010 0x00000011 0x00000000
acpicmos0 at acpi0
acpibat0 at acpi0: BAT0 model "01AV448" serial  2798 type LiP oem "Celxpert"
acpiac0 at acpi0: AC unit online
acpithinkpad0 at acpi0: version 2.0
"SMB0001" at acpi0 not configured
acpibtn1 at acpi0: LID_
acpibtn2 at acpi0: SLPB
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"STM7304" at acpi0 not configured
"USBC000" at acpi0 not configured
acpicpu0 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu1 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu2 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu3 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu4 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu5 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu6 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpicpu7 at acpi0: C2(0@400 io@0x414), C1(0@1 mwait), PSS
acpipwrres0 at acpi0: P0ST, resource for SATA
acpipwrres1 at acpi0: P3ST, resource for SATA
acpivideo0 at acpi0: VGA_
acpivout0 at acpivideo0: LCD_
cpu0: 1996 MHz: speeds: 2000 1700 1600 MHz
pci0 at mainbus0 bus 0
ksmn0 at pci0 dev 0 function 0 "AMD 17h/1xh Root Complex" rev 0x00
"AMD 17h/1xh IOMMU" rev 0x00 at pci0 dev 0 function 2 not configured
pchb0 at pci0 dev 1 function 0 "AMD 17h PCIE" rev 0x00
ppb0 at pci0 dev 1 function 1 "AMD 17h/1xh PCIE" rev 0x00: msi
pci1 at ppb0 bus 1
ppb1 at pci0 dev 1 function 2 "AMD 17h/1xh PCIE" rev 0x00: msi
pci2 at ppb1 bus 2
re0 at pci2 dev 0 function 0 "Realtek 8168" rev 0x10: RTL8168GU/8111GU (0x5080), msi, address e8:6a:64:f0:f8:14
rgephy0 at re0 phy 7: RTL8251 PHY, rev. 0
ppb2 at pci0 dev 1 function 3 "AMD 17h/1xh PCIE" rev 0x00: msi
pci3 at ppb2 bus 3
sdhc0 at pci3 dev 0 function 0 "O2 Micro 0Z8621 SD/MMC" rev 0x01: apic 33 int 8
sdhc0: SDHC 4.0, 50 MHz base clock
sdmmc0 at sdhc0: 4-bit, sd high-speed, mmc high-speed, ddr52, dma
ppb3 at pci0 dev 1 function 6 "AMD 17h/1xh PCIE" rev 0x00: msi
pci4 at ppb3 bus 4
iwm0 at pci4 dev 0 function 0 "Intel Dual Band Wireless-AC 8265" rev 0x78, msi
pchb1 at pci0 dev 8 function 0 "AMD 17h PCIE" rev 0x00
ppb4 at pci0 dev 8 function 1 "AMD 17h/1xh PCIE" rev 0x00
pci5 at ppb4 bus 5
amdgpu0 at pci5 dev 0 function 0 "ATI Radeon Vega" rev 0xc4
drm0 at amdgpu0
amdgpu0: msi
azalia0 at pci5 dev 0 function 1 "ATI Radeon Vega HD Audio" rev 0x00: msi
azalia0: no supported codecs
ccp0 at pci5 dev 0 function 2 "AMD 17h/1xh Crypto" rev 0x00
xhci0 at pci5 dev 0 function 3 "AMD 17h/1xh xHCI" rev 0x00: msi, xHCI 1.10
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "AMD xHCI root hub" rev 3.00/1.00 addr 1
xhci1 at pci5 dev 0 function 4 "AMD 17h/1xh xHCI" rev 0x00: msi, xHCI 1.10
usb1 at xhci1: USB revision 3.0
uhub1 at usb1 configuration 1 interface 0 "AMD xHCI root hub" rev 3.00/1.00 addr 1
azalia1 at pci5 dev 0 function 6 "AMD 17h/1xh HD Audio" rev 0x00: apic 33 int 30
azalia1: codecs: Conexant/0x5111
audio0 at azalia1
ppb5 at pci0 dev 8 function 2 "AMD 17h/1xh PCIE" rev 0x00
pci6 at ppb5 bus 6
ahci0 at pci6 dev 0 function 0 "AMD FCH AHCI" rev 0x61: msi, AHCI 1.3.1
ahci0: port 0: 6.0Gb/s
scsibus1 at ahci0: 32 targets
sd0 at scsibus1 targ 0 lun 0: <ATA, CT500MX500SSD1, M3CR> naa.500a0751e13ebe2f
sd0: 476940MB, 512 bytes/sector, 976773168 sectors, thin
piixpm0 at pci0 dev 20 function 0 "AMD FCH SMBus" rev 0x61: SMI
iic0 at piixpm0
spdmem0 at iic0 addr 0x50: 8GB DDR4 SDRAM PC4-19200 SO-DIMM
spdmem1 at iic0 addr 0x52: 8GB DDR4 SDRAM PC4-19200 SO-DIMM
iic1 at piixpm0
pcib0 at pci0 dev 20 function 3 "AMD FCH LPC" rev 0x51
pchb2 at pci0 dev 24 function 0 "AMD 17h/1xh Data Fabric" rev 0x00
pchb3 at pci0 dev 24 function 1 "AMD 17h/1xh Data Fabric" rev 0x00
pchb4 at pci0 dev 24 function 2 "AMD 17h/1xh Data Fabric" rev 0x00
pchb5 at pci0 dev 24 function 3 "AMD 17h/1xh Data Fabric" rev 0x00
pchb6 at pci0 dev 24 function 4 "AMD 17h/1xh Data Fabric" rev 0x00
pchb7 at pci0 dev 24 function 5 "AMD 17h/1xh Data Fabric" rev 0x00
pchb8 at pci0 dev 24 function 6 "AMD 17h/1xh Data Fabric" rev 0x00
pchb9 at pci0 dev 24 function 7 "AMD 17h/1xh Data Fabric" rev 0x00
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5 irq 1 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard
pms0 at pckbc0 (aux slot)
wsmouse0 at pms0 mux 0
wsmouse1 at pms0 mux 0
pms0: Synaptics clickpad, firmware 8.16, 0x1e2b1 0x940300 0x373740 0xf020a3 0x12e800
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
vmm0 at mainbus0: SVM/RVI
efifb at mainbus0 not configured
uaudio0 at uhub0 port 3 configuration 1 interface 1 "Plantronics Plantronics Headset" rev 1.10/0.04 addr 2
uaudio0: class v1, full-speed, sync, channels: 2 play, 2 rec, 9 ctls
audio1 at uaudio0
uhidev0 at uhub0 port 3 configuration 1 interface 3 "Plantronics Plantronics Headset" rev 1.10/0.04 addr 2
uhidev0: iclass 3/0
uhid0 at uhidev0: input=2, output=0, feature=0
uvideo0 at uhub1 port 2 configuration 1 interface 0 "Azurewave Integrated Camera" rev 2.01/17.11 addr 2
video0 at uvideo0
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on sd0a (3a85b6926424009b.a) swap on sd0b dump on sd0b
iwm0: hw rev 0x230, fw ver 34.0.1, address a0:51:0b:ed:56:de
amdgpu0: RAVEN 8 CU rev 0x01
amdgpu0: 1920x1080, 32bpp
wsdisplay0 at amdgpu0 mux 1: console (std, vt100 emulation), using wskbd0
wsdisplay0: screen 1-5 added (std, vt100 emulation)

usbdevs:
Controller /dev/usb0:
addr 01: 1022:0000 AMD, xHCI root hub
         super speed, self powered, config 1, rev 1.00
         driver: uhub0
addr 02: 047f:0ca1 Plantronics, Plantronics Headset
         full speed, power 100 mA, config 1, rev 0.04, iSerial 00500-0429034410003-V060000A
         driver: uaudio0
         driver: uhidev0
Controller /dev/usb1:
addr 01: 1022:0000 AMD, xHCI root hub
         super speed, self powered, config 1, rev 1.00
         driver: uhub1
addr 02: 13d3:56a6 Azurewave, Integrated Camera
         high speed, power 500 mA, config 1, rev 17.11, iSerial 0001
         driver: uvideo0

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Klemens Nanni-2
On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:

> >Synopsis: vmm/vmd fails to boot bsd.rd
> >Category: vmm
> >Environment:
> System      : OpenBSD 6.9
> Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>
> Architecture: OpenBSD.amd64
> Machine     : amd64
> >Description:
>
> vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> is able to be booted in this manner.
This is most likely due to the recent switch to compressed bsd.rd;
dry a gzcat(1)ed copy of bsd.rd instead.

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Josh Rickmar
On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:

> On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> > >Synopsis: vmm/vmd fails to boot bsd.rd
> > >Category: vmm
> > >Environment:
> > System      : OpenBSD 6.9
> > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> >
> > Architecture: OpenBSD.amd64
> > Machine     : amd64
> > >Description:
> >
> > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> > is able to be booted in this manner.
> This is most likely due to the recent switch to compressed bsd.rd;
> dry a gzcat(1)ed copy of bsd.rd instead.

Ah, yes this works.

Is this expected behavior or should vmd be taught how to read the
compressed kernel?

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Mike Larkin-2
On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:

> On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> > > >Synopsis: vmm/vmd fails to boot bsd.rd
> > > >Category: vmm
> > > >Environment:
> > > System      : OpenBSD 6.9
> > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > >
> > > Architecture: OpenBSD.amd64
> > > Machine     : amd64
> > > >Description:
> > >
> > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> > > is able to be booted in this manner.
> > This is most likely due to the recent switch to compressed bsd.rd;
> > dry a gzcat(1)ed copy of bsd.rd instead.
>
> Ah, yes this works.
>
> Is this expected behavior or should vmd be taught how to read the
> compressed kernel?
>

Sure. A diff would be welcome (libz is already in the tree and ready to use for
this).

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Josh Rickmar
On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:

> On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
> > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> > > > >Synopsis: vmm/vmd fails to boot bsd.rd
> > > > >Category: vmm
> > > > >Environment:
> > > > System      : OpenBSD 6.9
> > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > > >
> > > > Architecture: OpenBSD.amd64
> > > > Machine     : amd64
> > > > >Description:
> > > >
> > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> > > > is able to be booted in this manner.
> > > This is most likely due to the recent switch to compressed bsd.rd;
> > > dry a gzcat(1)ed copy of bsd.rd instead.
> >
> > Ah, yes this works.
> >
> > Is this expected behavior or should vmd be taught how to read the
> > compressed kernel?
> >
>
> Sure. A diff would be welcome (libz is already in the tree and ready to use for
> this).

I expect this may need some cleanup, but with this patch I am able to
boot the compressed bsd.rd.

It replaces passing the kernel image around as a FILE* to a wrapper
struct that may represent either a FILE* or gzFile.  The struct points
to a function pointer to dispatch to the correct read or seek
functions.

This isn't wrapping gztell, which is used to discover the size of the
bios firmware image, and so that will continue to error if you try to
load a compressed bios.  I don't think we would want to wrap that,
since seeking to the end to discover the size would result in
decompressing everything twice.

diff b711551f3ad0c8a480c9d1297568b8616c06bdec /usr/src
blob - 1770ac337a9996c76fb09de6f04909b3bb890658
file + usr.sbin/vmd/Makefile
--- usr.sbin/vmd/Makefile
+++ usr.sbin/vmd/Makefile
@@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 CFLAGS+= -Wsign-compare
 
-LDADD+= -lutil -lpthread -levent
+LDADD+= -lutil -lpthread -levent -lz
 DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
 
 YFLAGS=
blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
file + usr.sbin/vmd/loadfile.h
--- usr.sbin/vmd/loadfile.h
+++ usr.sbin/vmd/loadfile.h
@@ -73,8 +73,10 @@
 #define PML2_PAGE 0x13000
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
-int loadfile_elf(FILE *, struct vm_create_params *,
+struct bootimage;
+
+int loadfile_elf(struct bootimage *, struct vm_create_params *,
     struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
-size_t mread(FILE *, paddr_t, size_t);
+size_t mread(struct bootimage *, paddr_t, size_t);
 
blob - 116094260948b50b9f1eda63d3241b77bfddb39d
file + usr.sbin/vmd/loadfile_elf.c
--- usr.sbin/vmd/loadfile_elf.c
+++ usr.sbin/vmd/loadfile_elf.c
@@ -115,8 +115,8 @@ union {
 
 static void setsegment(struct mem_segment_descriptor *, uint32_t,
     size_t, int, int, int, int);
-static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
-static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
+static int elf32_exec(struct bootimage *, Elf32_Ehdr *, u_long *, int);
+static int elf64_exec(struct bootimage *, 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, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
@@ -263,7 +263,7 @@ push_pt_64(void)
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_elf(FILE *fp, struct vm_create_params *vcp,
+loadfile_elf(struct bootimage *f, struct vm_create_params *vcp,
     struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
     unsigned int bootdevice)
 {
@@ -274,17 +274,17 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
  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))
+ if ((r = f->ops->read(f, &hdr, sizeof(hdr))) != sizeof(hdr))
  return 1;
 
  memset(&marks, 0, sizeof(marks));
  if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
- r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
+ r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
  is_i386 = 1;
  } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
- r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
+ r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
  } else
  errno = ENOEXEC;
 
@@ -490,7 +490,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  * into the guest address space at paddr 'addr'.
  *
  * Parameters:
- *  fd: file descriptor of the kernel image file to read from.
+ *  f: kernel image file to read from.
  *  addr: guest paddr_t to load to
  *  sz: number of bytes to load
  *
@@ -498,7 +498,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  *  returns 'sz' if successful, or 0 otherwise.
  */
 size_t
-mread(FILE *fp, paddr_t addr, size_t sz)
+mread(struct bootimage *f, paddr_t addr, size_t sz)
 {
  size_t ct;
  size_t i, rd, osz;
@@ -518,7 +518,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = sz;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if (f->ops->read(f, buf, ct) != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -542,7 +542,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = PAGE_SIZE;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if (f->ops->read(f, buf, ct) != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -665,7 +665,7 @@ mbcopy(void *src, paddr_t dst, int sz)
  *  1 if unsuccessful
  */
 static int
-elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
+elf64_exec(struct bootimage *f, Elf64_Ehdr *elf, u_long *marks, int flags)
 {
  Elf64_Shdr *shp;
  Elf64_Phdr *phdr;
@@ -680,12 +680,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf64_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if (f->ops->read(f, phdr, sz) != sz) {
  free(phdr);
  return 1;
  }
@@ -725,12 +725,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (f->ops->seek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -770,14 +770,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf64_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf64_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if (f->ops->read(f, shp, sz) != sz) {
  free(shp);
  return 1;
  }
@@ -787,13 +787,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -816,13 +816,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
     !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (f->ops->seek(f,
+    (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
@@ -875,7 +876,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  * This function is used for 32 bit kernels.
  *
  * Parameters:
- *  fd: file descriptor of the kernel to load
+ *  f: kernel file to load
  *  elf: ELF header of the kernel
  *  marks: array to store the offsets of various kernel structures
  *      (start, bss, etc)
@@ -887,7 +888,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  *  1 if unsuccessful
  */
 static int
-elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
+elf32_exec(struct bootimage *f, Elf32_Ehdr *elf, u_long *marks, int flags)
 {
  Elf32_Shdr *shp;
  Elf32_Phdr *phdr;
@@ -902,12 +903,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf32_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if (f->ops->read(f, phdr, sz) != sz) {
  free(phdr);
  return 1;
  }
@@ -947,12 +948,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (f->ops->seek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -992,14 +993,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf32_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf32_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if (f->ops->read(f, shp, sz) != sz) {
  free(shp);
  return 1;
  }
@@ -1009,13 +1010,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -1037,13 +1038,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     shp[i].sh_type == SHT_STRTAB ||
     !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (f->ops->seek(f,
+    (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
file + usr.sbin/vmd/vm.c
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -84,7 +84,7 @@ void vcpu_exit_inout(struct vm_run_params *);
 int vcpu_exit_eptviolation(struct vm_run_params *);
 uint8_t vcpu_exit_pci(struct vm_run_params *);
 int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
-int loadfile_bios(FILE *, struct vcpu_reg_state *);
+int loadfile_bios(struct bootimage *, struct vcpu_reg_state *);
 int send_vm(int, struct vm_create_params *);
 int dump_send_header(int);
 int dump_vmr(int , struct vm_mem_range *);
@@ -212,7 +212,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  * directly into memory.
  *
  * Parameters:
- *  fp: file of a kernel file to load
+ *  f: BIOS file to load
  *  (out) vrs: register state to set on init for this kernel
  *
  * Return values:
@@ -220,7 +220,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
+loadfile_bios(struct bootimage *f, struct vcpu_reg_state *vrs)
 {
  off_t size, off;
 
@@ -228,8 +228,10 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
  memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
 
  /* Get the size of the BIOS image and seek to the beginning */
- if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
-    fseeko(fp, 0, SEEK_SET) == -1)
+ if (f->type != FILE_STDIO)
+ return (-1); /* XXX: we don't wrap gztell */
+ if (f->ops->seek(f, 0, SEEK_END) == -1 || (size = ftello(f->f)) == -1 ||
+    f->ops->seek(f, 0, SEEK_SET) == -1)
  return (-1);
 
  /* The BIOS image must end at 1M */
@@ -237,7 +239,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
  return (-1);
 
  /* Read BIOS image into memory */
- if (mread(fp, off, size) != (size_t)size) {
+ if (mread(f, off, size) != (size_t)size) {
  errno = EIO;
  return (-1);
  }
@@ -277,7 +279,7 @@ start_vm(struct vmd_vm *vm, int fd)
  struct vcpu_reg_state vrs;
  int nicfds[VMM_MAX_NICS_PER_VM];
  int ret;
- FILE *fp;
+ struct bootimage *f;
  struct vmboot_params vmboot;
  size_t i;
  struct vm_rwregs_params  vrp;
@@ -332,13 +334,13 @@ start_vm(struct vmd_vm *vm, int fd)
  memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
 
  /* Find and open kernel image */
- if ((fp = vmboot_open(vm->vm_kernel,
+ if ((f = vmboot_open(vm->vm_kernel,
     vm->vm_disks[0], vmc->vmc_diskbases[0],
     vmc->vmc_disktypes[0], &vmboot)) == NULL)
  fatalx("failed to open kernel - exiting");
 
  /* Load kernel image */
- ret = loadfile_elf(fp, vcp, &vrs,
+ ret = loadfile_elf(f, vcp, &vrs,
     vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
  /*
@@ -346,12 +348,12 @@ start_vm(struct vmd_vm *vm, int fd)
  * with vm->vm_kernel and not loaded from the disk)
  */
  if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
- ret = loadfile_bios(fp, &vrs);
+ ret = loadfile_bios(f, &vrs);
 
  if (ret)
  fatal("failed to load kernel or BIOS - exiting");
 
- vmboot_close(fp, &vmboot);
+ vmboot_close(f, &vmboot);
  }
 
  if (vm->vm_kernel != -1)
blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
file + usr.sbin/vmd/vmboot.c
--- usr.sbin/vmd/vmboot.c
+++ usr.sbin/vmd/vmboot.c
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <err.h>
 #include <vis.h>
+#include <zlib.h>
 
 #include "vmd.h"
 #include "vmboot.h"
@@ -46,6 +47,9 @@ int vmboot_strategy(void *, int, daddr_t, size_t, voi
 off_t vmboot_findopenbsd(struct open_file *, off_t, struct disklabel *);
 void *vmboot_loadfile(struct open_file *, char *, size_t *);
 
+static struct bootimage *vmboot_fdopen(int);
+static struct bootimage *wrap_stdio(FILE *);
+
 int
 vmboot_bootcmd(char *line, struct vmboot_params *bp)
 {
@@ -384,7 +388,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
  return (p);
 }
 
-FILE *
+struct bootimage *
 vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
     struct vmboot_params *vmboot)
 {
@@ -392,6 +396,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
  char *buf = NULL;
  size_t size;
  FILE *fp = NULL;
+ struct bootimage *f = NULL;
  struct disklabel dl;
  struct virtio_backing *vfp;
  off_t sz;
@@ -402,7 +407,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
 
  /* First open kernel directly if specified by fd */
  if (kernel_fd != -1)
- return (fdopen(kernel_fd, "r"));
+ return (vmboot_fdopen(kernel_fd));
 
  if (disk_fd == NULL || nfd < 1)
  return (NULL);
@@ -481,21 +486,127 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
     vmboot->vbp_device, vmboot->vbp_image);
  }
 
- return (fp);
+ if ((f = wrap_stdio(fp)) == NULL)
+ goto fail;
+
+ return (f);
   fail:
- vmboot_close(fp, vmboot);
+ vmboot_close(f, vmboot);
  return (NULL);
 }
 
 void
-vmboot_close(FILE *fp, struct vmboot_params *vmboot)
+vmboot_close(struct bootimage *f, struct vmboot_params *vmboot)
 {
  struct virtio_backing *vfp = vmboot->vbp_arg;
 
- if (fp != NULL)
- fclose(fp);
+ switch (f->type) {
+ case FILE_STDIO:
+ fclose(f->f);
+ break;
+ case FILE_GZIP:
+ gzclose(f->gzf);
+ break;
+ default:
+ /* can't happen */
+ errx(2, "invalid file type");
+ }
+
  if (vfp != NULL)
  vfp->close(vfp->p, 1);
+ free(f);
  free(vmboot->vbp_arg);
  free(vmboot->vbp_buf);
 }
+
+size_t
+stdio_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+ if (f->type != FILE_STDIO)
+ return (0);
+ return (fread(ptr, 1, nbytes, f->f));
+}
+
+int
+stdio_seek(struct bootimage *f, off_t offset, int whence)
+{
+ if (f->type != FILE_STDIO)
+ return (-1); /* XXX set errno? */
+ return (fseeko(f->f, offset, whence));
+}
+
+
+size_t
+gzip_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+ if (f->type != FILE_GZIP)
+ return (0); /* XXX set errno? */
+ return ((ssize_t)gzread(f->gzf, ptr, nbytes));
+}
+
+int
+gzip_seek(struct bootimage *f, off_t offset, int whence)
+{
+ if (f->type != FILE_GZIP)
+ return (-1); /* XXX set errno? */
+ return ((int)gzseek(f->gzf, offset, whence));
+}
+
+static const struct bootimage_ops stdio_ops = {
+ stdio_read,
+ stdio_seek,
+};
+static const struct bootimage_ops gzip_ops = {
+ gzip_read,
+ gzip_seek,
+};
+
+static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+static struct bootimage *
+vmboot_fdopen(int fd)
+{
+ struct bootimage *f;
+ struct stat sb;
+ u_char magic[2];
+
+ if (fstat(fd, &sb) == -1)
+ return (NULL);
+ if (S_ISDIR(sb.st_mode)) {
+ errno = EISDIR;
+ return (NULL);
+ }
+
+ if ((f = calloc(1, sizeof *f)) == NULL)
+ return (NULL);
+
+ if (pread(fd, magic, sizeof(magic), 0) != 2)
+ return NULL;
+ if (magic[0] == gz_magic[0] && magic[1] == gz_magic[1]) {
+ f->type = FILE_GZIP;
+ f->ops = &gzip_ops;
+ if ((f->gzf = gzdopen(fd, "r")) != NULL)
+ return f;
+ } else {
+ f->type = FILE_STDIO;
+ f->ops = &stdio_ops;
+ if ((f->f = fdopen(fd, "r")) != NULL)
+ return f;
+ }
+
+ free(f);
+ return NULL;
+}
+
+static struct bootimage *
+wrap_stdio(FILE *fp)
+{
+ struct bootimage *f;
+
+ if ((f = calloc(1, sizeof *f)) == NULL)
+ return (NULL);
+ f->type = FILE_STDIO;
+ f->ops = &stdio_ops;
+ f->f = fp;
+ return (f);
+}
blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
file + usr.sbin/vmd/vmd.h
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -30,6 +30,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <pthread.h>
+#include <zlib.h>
 
 #include "proc.h"
 
@@ -475,9 +476,31 @@ int config_getif(struct privsep *, struct imsg *);
 int config_getcdrom(struct privsep *, struct imsg *);
 
 /* vmboot.c */
-FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
-void vmboot_close(FILE *, struct vmboot_params *);
+struct bootimage_ops;
 
+struct bootimage {
+ int type;
+#define FILE_STDIO 0
+#define FILE_GZIP 1
+ FILE *f;
+ gzFile *gzf;
+ struct bootimage_ops const *ops;
+};
+
+struct bootimage_ops {
+ size_t (*read)(struct bootimage *, void *, size_t);
+ int (*seek)(struct bootimage *, off_t, int);
+};
+
+size_t stdio_read(struct bootimage *f, void *, size_t);
+int stdio_seek(struct bootimage *, off_t, int);
+size_t gzip_read(struct bootimage *f, void *, size_t);
+int gzip_seek(struct bootimage *, off_t, int);
+
+struct bootimage *vmboot_open(int, int *, int, unsigned int,
+    struct vmboot_params *);
+void vmboot_close(struct bootimage *, struct vmboot_params *);
+
 /* parse.y */
 int parse_config(const char *);
 int cmdline_symset(char *);

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Josh Rickmar
On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote:

> On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
> > On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
> > > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> > > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> > > > > >Synopsis: vmm/vmd fails to boot bsd.rd
> > > > > >Category: vmm
> > > > > >Environment:
> > > > > System      : OpenBSD 6.9
> > > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> > > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> > > > >
> > > > > Architecture: OpenBSD.amd64
> > > > > Machine     : amd64
> > > > > >Description:
> > > > >
> > > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> > > > > is able to be booted in this manner.
> > > > This is most likely due to the recent switch to compressed bsd.rd;
> > > > dry a gzcat(1)ed copy of bsd.rd instead.
> > >
> > > Ah, yes this works.
> > >
> > > Is this expected behavior or should vmd be taught how to read the
> > > compressed kernel?
> > >
> >
> > Sure. A diff would be welcome (libz is already in the tree and ready to use for
> > this).
>
> I expect this may need some cleanup, but with this patch I am able to
> boot the compressed bsd.rd.
>
> It replaces passing the kernel image around as a FILE* to a wrapper
> struct that may represent either a FILE* or gzFile.  The struct points
> to a function pointer to dispatch to the correct read or seek
> functions.
>
> This isn't wrapping gztell, which is used to discover the size of the
> bios firmware image, and so that will continue to error if you try to
> load a compressed bios.  I don't think we would want to wrap that,
> since seeking to the end to discover the size would result in
> decompressing everything twice.

Hmm, let's rename "stdio" to "stream" for the regular uncompressed
files.  Otherwise this diff is the same as before.

diff b711551f3ad0c8a480c9d1297568b8616c06bdec /usr/src
blob - 1770ac337a9996c76fb09de6f04909b3bb890658
file + usr.sbin/vmd/Makefile
--- usr.sbin/vmd/Makefile
+++ usr.sbin/vmd/Makefile
@@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 CFLAGS+= -Wsign-compare
 
-LDADD+= -lutil -lpthread -levent
+LDADD+= -lutil -lpthread -levent -lz
 DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
 
 YFLAGS=
blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
file + usr.sbin/vmd/loadfile.h
--- usr.sbin/vmd/loadfile.h
+++ usr.sbin/vmd/loadfile.h
@@ -73,8 +73,10 @@
 #define PML2_PAGE 0x13000
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
-int loadfile_elf(FILE *, struct vm_create_params *,
+struct bootimage;
+
+int loadfile_elf(struct bootimage *, struct vm_create_params *,
     struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
-size_t mread(FILE *, paddr_t, size_t);
+size_t mread(struct bootimage *, paddr_t, size_t);
 
blob - 116094260948b50b9f1eda63d3241b77bfddb39d
file + usr.sbin/vmd/loadfile_elf.c
--- usr.sbin/vmd/loadfile_elf.c
+++ usr.sbin/vmd/loadfile_elf.c
@@ -115,8 +115,8 @@ union {
 
 static void setsegment(struct mem_segment_descriptor *, uint32_t,
     size_t, int, int, int, int);
-static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
-static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
+static int elf32_exec(struct bootimage *, Elf32_Ehdr *, u_long *, int);
+static int elf64_exec(struct bootimage *, 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, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
@@ -263,7 +263,7 @@ push_pt_64(void)
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_elf(FILE *fp, struct vm_create_params *vcp,
+loadfile_elf(struct bootimage *f, struct vm_create_params *vcp,
     struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
     unsigned int bootdevice)
 {
@@ -274,17 +274,17 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
  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))
+ if ((r = f->ops->read(f, &hdr, sizeof(hdr))) != sizeof(hdr))
  return 1;
 
  memset(&marks, 0, sizeof(marks));
  if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
- r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
+ r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
  is_i386 = 1;
  } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
- r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
+ r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
  } else
  errno = ENOEXEC;
 
@@ -490,7 +490,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  * into the guest address space at paddr 'addr'.
  *
  * Parameters:
- *  fd: file descriptor of the kernel image file to read from.
+ *  f: kernel image file to read from.
  *  addr: guest paddr_t to load to
  *  sz: number of bytes to load
  *
@@ -498,7 +498,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  *  returns 'sz' if successful, or 0 otherwise.
  */
 size_t
-mread(FILE *fp, paddr_t addr, size_t sz)
+mread(struct bootimage *f, paddr_t addr, size_t sz)
 {
  size_t ct;
  size_t i, rd, osz;
@@ -518,7 +518,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = sz;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if (f->ops->read(f, buf, ct) != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -542,7 +542,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = PAGE_SIZE;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if (f->ops->read(f, buf, ct) != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -665,7 +665,7 @@ mbcopy(void *src, paddr_t dst, int sz)
  *  1 if unsuccessful
  */
 static int
-elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
+elf64_exec(struct bootimage *f, Elf64_Ehdr *elf, u_long *marks, int flags)
 {
  Elf64_Shdr *shp;
  Elf64_Phdr *phdr;
@@ -680,12 +680,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf64_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if (f->ops->read(f, phdr, sz) != sz) {
  free(phdr);
  return 1;
  }
@@ -725,12 +725,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (f->ops->seek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -770,14 +770,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf64_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf64_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if (f->ops->read(f, shp, sz) != sz) {
  free(shp);
  return 1;
  }
@@ -787,13 +787,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -816,13 +816,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
     !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (f->ops->seek(f,
+    (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
@@ -875,7 +876,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  * This function is used for 32 bit kernels.
  *
  * Parameters:
- *  fd: file descriptor of the kernel to load
+ *  f: kernel file to load
  *  elf: ELF header of the kernel
  *  marks: array to store the offsets of various kernel structures
  *      (start, bss, etc)
@@ -887,7 +888,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  *  1 if unsuccessful
  */
 static int
-elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
+elf32_exec(struct bootimage *f, Elf32_Ehdr *elf, u_long *marks, int flags)
 {
  Elf32_Shdr *shp;
  Elf32_Phdr *phdr;
@@ -902,12 +903,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf32_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if (f->ops->read(f, phdr, sz) != sz) {
  free(phdr);
  return 1;
  }
@@ -947,12 +948,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (f->ops->seek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -992,14 +993,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf32_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf32_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if (f->ops->read(f, shp, sz) != sz) {
  free(shp);
  return 1;
  }
@@ -1009,13 +1010,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -1037,13 +1038,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     shp[i].sh_type == SHT_STRTAB ||
     !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (f->ops->seek(f,
+    (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
file + usr.sbin/vmd/vm.c
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -84,7 +84,7 @@ void vcpu_exit_inout(struct vm_run_params *);
 int vcpu_exit_eptviolation(struct vm_run_params *);
 uint8_t vcpu_exit_pci(struct vm_run_params *);
 int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
-int loadfile_bios(FILE *, struct vcpu_reg_state *);
+int loadfile_bios(struct bootimage *, struct vcpu_reg_state *);
 int send_vm(int, struct vm_create_params *);
 int dump_send_header(int);
 int dump_vmr(int , struct vm_mem_range *);
@@ -212,7 +212,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  * directly into memory.
  *
  * Parameters:
- *  fp: file of a kernel file to load
+ *  f: BIOS file to load
  *  (out) vrs: register state to set on init for this kernel
  *
  * Return values:
@@ -220,7 +220,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
+loadfile_bios(struct bootimage *f, struct vcpu_reg_state *vrs)
 {
  off_t size, off;
 
@@ -228,8 +228,10 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
  memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
 
  /* Get the size of the BIOS image and seek to the beginning */
- if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
-    fseeko(fp, 0, SEEK_SET) == -1)
+ if (f->type != FILE_STREAM)
+ return (-1); /* XXX: we don't wrap gztell */
+ if (f->ops->seek(f, 0, SEEK_END) == -1 || (size = ftello(f->f)) == -1 ||
+    f->ops->seek(f, 0, SEEK_SET) == -1)
  return (-1);
 
  /* The BIOS image must end at 1M */
@@ -237,7 +239,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
  return (-1);
 
  /* Read BIOS image into memory */
- if (mread(fp, off, size) != (size_t)size) {
+ if (mread(f, off, size) != (size_t)size) {
  errno = EIO;
  return (-1);
  }
@@ -277,7 +279,7 @@ start_vm(struct vmd_vm *vm, int fd)
  struct vcpu_reg_state vrs;
  int nicfds[VMM_MAX_NICS_PER_VM];
  int ret;
- FILE *fp;
+ struct bootimage *f;
  struct vmboot_params vmboot;
  size_t i;
  struct vm_rwregs_params  vrp;
@@ -332,13 +334,13 @@ start_vm(struct vmd_vm *vm, int fd)
  memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
 
  /* Find and open kernel image */
- if ((fp = vmboot_open(vm->vm_kernel,
+ if ((f = vmboot_open(vm->vm_kernel,
     vm->vm_disks[0], vmc->vmc_diskbases[0],
     vmc->vmc_disktypes[0], &vmboot)) == NULL)
  fatalx("failed to open kernel - exiting");
 
  /* Load kernel image */
- ret = loadfile_elf(fp, vcp, &vrs,
+ ret = loadfile_elf(f, vcp, &vrs,
     vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
  /*
@@ -346,12 +348,12 @@ start_vm(struct vmd_vm *vm, int fd)
  * with vm->vm_kernel and not loaded from the disk)
  */
  if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
- ret = loadfile_bios(fp, &vrs);
+ ret = loadfile_bios(f, &vrs);
 
  if (ret)
  fatal("failed to load kernel or BIOS - exiting");
 
- vmboot_close(fp, &vmboot);
+ vmboot_close(f, &vmboot);
  }
 
  if (vm->vm_kernel != -1)
blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
file + usr.sbin/vmd/vmboot.c
--- usr.sbin/vmd/vmboot.c
+++ usr.sbin/vmd/vmboot.c
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <err.h>
 #include <vis.h>
+#include <zlib.h>
 
 #include "vmd.h"
 #include "vmboot.h"
@@ -46,6 +47,9 @@ int vmboot_strategy(void *, int, daddr_t, size_t, voi
 off_t vmboot_findopenbsd(struct open_file *, off_t, struct disklabel *);
 void *vmboot_loadfile(struct open_file *, char *, size_t *);
 
+static struct bootimage *vmboot_fdopen(int);
+static struct bootimage *wrap_stream(FILE *);
+
 int
 vmboot_bootcmd(char *line, struct vmboot_params *bp)
 {
@@ -384,7 +388,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
  return (p);
 }
 
-FILE *
+struct bootimage *
 vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
     struct vmboot_params *vmboot)
 {
@@ -392,6 +396,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
  char *buf = NULL;
  size_t size;
  FILE *fp = NULL;
+ struct bootimage *f = NULL;
  struct disklabel dl;
  struct virtio_backing *vfp;
  off_t sz;
@@ -402,7 +407,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
 
  /* First open kernel directly if specified by fd */
  if (kernel_fd != -1)
- return (fdopen(kernel_fd, "r"));
+ return (vmboot_fdopen(kernel_fd));
 
  if (disk_fd == NULL || nfd < 1)
  return (NULL);
@@ -481,21 +486,127 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
     vmboot->vbp_device, vmboot->vbp_image);
  }
 
- return (fp);
+ if ((f = wrap_stream(fp)) == NULL)
+ goto fail;
+
+ return (f);
   fail:
- vmboot_close(fp, vmboot);
+ vmboot_close(f, vmboot);
  return (NULL);
 }
 
 void
-vmboot_close(FILE *fp, struct vmboot_params *vmboot)
+vmboot_close(struct bootimage *f, struct vmboot_params *vmboot)
 {
  struct virtio_backing *vfp = vmboot->vbp_arg;
 
- if (fp != NULL)
- fclose(fp);
+ switch (f->type) {
+ case FILE_STREAM:
+ fclose(f->f);
+ break;
+ case FILE_GZIP:
+ gzclose(f->gzf);
+ break;
+ default:
+ /* can't happen */
+ errx(2, "invalid file type");
+ }
+
  if (vfp != NULL)
  vfp->close(vfp->p, 1);
+ free(f);
  free(vmboot->vbp_arg);
  free(vmboot->vbp_buf);
 }
+
+size_t
+stream_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+ if (f->type != FILE_STREAM)
+ return (0);
+ return (fread(ptr, 1, nbytes, f->f));
+}
+
+int
+stream_seek(struct bootimage *f, off_t offset, int whence)
+{
+ if (f->type != FILE_STREAM)
+ return (-1); /* XXX set errno? */
+ return (fseeko(f->f, offset, whence));
+}
+
+
+size_t
+gzip_read(struct bootimage *f, void *ptr, size_t nbytes)
+{
+ if (f->type != FILE_GZIP)
+ return (0); /* XXX set errno? */
+ return ((ssize_t)gzread(f->gzf, ptr, nbytes));
+}
+
+int
+gzip_seek(struct bootimage *f, off_t offset, int whence)
+{
+ if (f->type != FILE_GZIP)
+ return (-1); /* XXX set errno? */
+ return ((int)gzseek(f->gzf, offset, whence));
+}
+
+static const struct bootimage_ops stream_ops = {
+ stream_read,
+ stream_seek,
+};
+static const struct bootimage_ops gzip_ops = {
+ gzip_read,
+ gzip_seek,
+};
+
+static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+static struct bootimage *
+vmboot_fdopen(int fd)
+{
+ struct bootimage *f;
+ struct stat sb;
+ u_char magic[2];
+
+ if (fstat(fd, &sb) == -1)
+ return (NULL);
+ if (S_ISDIR(sb.st_mode)) {
+ errno = EISDIR;
+ return (NULL);
+ }
+
+ if ((f = calloc(1, sizeof *f)) == NULL)
+ return (NULL);
+
+ if (pread(fd, magic, sizeof(magic), 0) != 2)
+ return NULL;
+ if (magic[0] == gz_magic[0] && magic[1] == gz_magic[1]) {
+ f->type = FILE_GZIP;
+ f->ops = &gzip_ops;
+ if ((f->gzf = gzdopen(fd, "r")) != NULL)
+ return f;
+ } else {
+ f->type = FILE_STREAM;
+ f->ops = &stream_ops;
+ if ((f->f = fdopen(fd, "r")) != NULL)
+ return f;
+ }
+
+ free(f);
+ return NULL;
+}
+
+static struct bootimage *
+wrap_stream(FILE *fp)
+{
+ struct bootimage *f;
+
+ if ((f = calloc(1, sizeof *f)) == NULL)
+ return (NULL);
+ f->type = FILE_STREAM;
+ f->ops = &stream_ops;
+ f->f = fp;
+ return (f);
+}
blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
file + usr.sbin/vmd/vmd.h
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -30,6 +30,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <pthread.h>
+#include <zlib.h>
 
 #include "proc.h"
 
@@ -475,9 +476,31 @@ int config_getif(struct privsep *, struct imsg *);
 int config_getcdrom(struct privsep *, struct imsg *);
 
 /* vmboot.c */
-FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
-void vmboot_close(FILE *, struct vmboot_params *);
+struct bootimage_ops;
 
+struct bootimage {
+ int type;
+#define FILE_STREAM 0
+#define FILE_GZIP 1
+ FILE *f;
+ gzFile *gzf;
+ struct bootimage_ops const *ops;
+};
+
+struct bootimage_ops {
+ size_t (*read)(struct bootimage *, void *, size_t);
+ int (*seek)(struct bootimage *, off_t, int);
+};
+
+size_t stream_read(struct bootimage *f, void *, size_t);
+int stream_seek(struct bootimage *, off_t, int);
+size_t gzip_read(struct bootimage *f, void *, size_t);
+int gzip_seek(struct bootimage *, off_t, int);
+
+struct bootimage *vmboot_open(int, int *, int, unsigned int,
+    struct vmboot_params *);
+void vmboot_close(struct bootimage *, struct vmboot_params *);
+
 /* parse.y */
 int parse_config(const char *);
 int cmdline_symset(char *);

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Dave Voutila-2

Josh Rickmar writes:

> On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote:
>> On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
>> > On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
>> > > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
>> > > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
>> > > > > >Synopsis: vmm/vmd fails to boot bsd.rd
>> > > > > >Category: vmm
>> > > > > >Environment:
>> > > > > System      : OpenBSD 6.9
>> > > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
>> > > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>> > > > >
>> > > > > Architecture: OpenBSD.amd64
>> > > > > Machine     : amd64
>> > > > > >Description:
>> > > > >
>> > > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
>> > > > > is able to be booted in this manner.
>> > > > This is most likely due to the recent switch to compressed bsd.rd;
>> > > > dry a gzcat(1)ed copy of bsd.rd instead.
>> > >
>> > > Ah, yes this works.
>> > >
>> > > Is this expected behavior or should vmd be taught how to read the
>> > > compressed kernel?
>> > >
>> >
>> > Sure. A diff would be welcome (libz is already in the tree and ready to use for
>> > this).
>>
>> I expect this may need some cleanup, but with this patch I am able to
>> boot the compressed bsd.rd.
>>
>> It replaces passing the kernel image around as a FILE* to a wrapper
>> struct that may represent either a FILE* or gzFile.  The struct points
>> to a function pointer to dispatch to the correct read or seek
>> functions.
>>
>> This isn't wrapping gztell, which is used to discover the size of the
>> bios firmware image, and so that will continue to error if you try to
>> load a compressed bios.  I don't think we would want to wrap that,
>> since seeking to the end to discover the size would result in
>> decompressing everything twice.
>
> Hmm, let's rename "stdio" to "stream" for the regular uncompressed
> files.  Otherwise this diff is the same as before.

I believe you can simplify this and assume the file is gzip compressed
and wrap the file descriptor with a call to gzdopen(3) to create a
gzFile. The gz{read,write,tell,etc.}(3) calls should operate on both
gzip compressed and non-compressed files (in "transparent mode").

That's at least my experience using gzdopen(3) and gzread(3).

>
> diff b711551f3ad0c8a480c9d1297568b8616c06bdec /usr/src
> blob - 1770ac337a9996c76fb09de6f04909b3bb890658
> file + usr.sbin/vmd/Makefile
> --- usr.sbin/vmd/Makefile
> +++ usr.sbin/vmd/Makefile
> @@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
>  CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
>  CFLAGS+= -Wsign-compare
>
> -LDADD+= -lutil -lpthread -levent
> +LDADD+= -lutil -lpthread -levent -lz
>  DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
>
>  YFLAGS=
> blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
> file + usr.sbin/vmd/loadfile.h
> --- usr.sbin/vmd/loadfile.h
> +++ usr.sbin/vmd/loadfile.h
> @@ -73,8 +73,10 @@
>  #define PML2_PAGE 0x13000
>  #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
>
> -int loadfile_elf(FILE *, struct vm_create_params *,
> +struct bootimage;
> +
> +int loadfile_elf(struct bootimage *, struct vm_create_params *,
>      struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
>
> -size_t mread(FILE *, paddr_t, size_t);
> +size_t mread(struct bootimage *, paddr_t, size_t);
>
> blob - 116094260948b50b9f1eda63d3241b77bfddb39d
> file + usr.sbin/vmd/loadfile_elf.c
> --- usr.sbin/vmd/loadfile_elf.c
> +++ usr.sbin/vmd/loadfile_elf.c
> @@ -115,8 +115,8 @@ union {
>
>  static void setsegment(struct mem_segment_descriptor *, uint32_t,
>      size_t, int, int, int, int);
> -static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
> -static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
> +static int elf32_exec(struct bootimage *, Elf32_Ehdr *, u_long *, int);
> +static int elf64_exec(struct bootimage *, 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, bios_bootmac_t *);
>  static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
> @@ -263,7 +263,7 @@ push_pt_64(void)
>   *  various error codes returned from read(2) or loadelf functions
>   */
>  int
> -loadfile_elf(FILE *fp, struct vm_create_params *vcp,
> +loadfile_elf(struct bootimage *f, struct vm_create_params *vcp,
>      struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
>      unsigned int bootdevice)
>  {
> @@ -274,17 +274,17 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
>   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))
> + if ((r = f->ops->read(f, &hdr, sizeof(hdr))) != sizeof(hdr))
>   return 1;
>
>   memset(&marks, 0, sizeof(marks));
>   if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
>      hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
> - r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
> + r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
>   is_i386 = 1;
>   } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
>      hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
> - r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
> + r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
>   } else
>   errno = ENOEXEC;
>
> @@ -490,7 +490,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
>   * into the guest address space at paddr 'addr'.
>   *
>   * Parameters:
> - *  fd: file descriptor of the kernel image file to read from.
> + *  f: kernel image file to read from.
>   *  addr: guest paddr_t to load to
>   *  sz: number of bytes to load
>   *
> @@ -498,7 +498,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
>   *  returns 'sz' if successful, or 0 otherwise.
>   */
>  size_t
> -mread(FILE *fp, paddr_t addr, size_t sz)
> +mread(struct bootimage *f, paddr_t addr, size_t sz)
>  {
>   size_t ct;
>   size_t i, rd, osz;
> @@ -518,7 +518,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
>   else
>   ct = sz;
>
> - if (fread(buf, 1, ct, fp) != ct) {
> + if (f->ops->read(f, buf, ct) != ct) {
>   log_warn("%s: error %d in mread", __progname, errno);
>   return (0);
>   }
> @@ -542,7 +542,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
>   else
>   ct = PAGE_SIZE;
>
> - if (fread(buf, 1, ct, fp) != ct) {
> + if (f->ops->read(f, buf, ct) != ct) {
>   log_warn("%s: error %d in mread", __progname, errno);
>   return (0);
>   }
> @@ -665,7 +665,7 @@ mbcopy(void *src, paddr_t dst, int sz)
>   *  1 if unsuccessful
>   */
>  static int
> -elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
> +elf64_exec(struct bootimage *f, Elf64_Ehdr *elf, u_long *marks, int flags)
>  {
>   Elf64_Shdr *shp;
>   Elf64_Phdr *phdr;
> @@ -680,12 +680,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   sz = elf->e_phnum * sizeof(Elf64_Phdr);
>   phdr = malloc(sz);
>
> - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> + if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
>   free(phdr);
>   return 1;
>   }
>
> - if (fread(phdr, 1, sz, fp) != sz) {
> + if (f->ops->read(f, phdr, sz) != sz) {
>   free(phdr);
>   return 1;
>   }
> @@ -725,12 +725,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
>
>   /* Read in segment. */
> - if (fseeko(fp, (off_t)phdr[i].p_offset,
> + if (f->ops->seek(f, (off_t)phdr[i].p_offset,
>      SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
> - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
>      phdr[i].p_filesz) {
>   free(phdr);
>   return 1;
> @@ -770,14 +770,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   maxp += sizeof(Elf64_Ehdr);
>
>   if (flags & (LOAD_SYM | COUNT_SYM)) {
> - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> + if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
>   warn("lseek section headers");
>   return 1;
>   }
>   sz = elf->e_shnum * sizeof(Elf64_Shdr);
>   shp = malloc(sz);
>
> - if (fread(shp, 1, sz, fp) != sz) {
> + if (f->ops->read(f, shp, sz) != sz) {
>   free(shp);
>   return 1;
>   }
> @@ -787,13 +787,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>
>   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
>   char *shstr = malloc(shstrsz);
> - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> + if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> + if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
>   free(shstr);
>   free(shp);
>   return 1;
> @@ -816,13 +816,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>      !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
>      !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
>   if (havesyms && (flags & LOAD_SYM)) {
> - if (fseeko(fp, (off_t)shp[i].sh_offset,
> + if (f->ops->seek(f,
> +    (off_t)shp[i].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (mread(fp, maxp,
> + if (mread(f, maxp,
>      shp[i].sh_size) != shp[i].sh_size) {
>   free(shstr);
>   free(shp);
> @@ -875,7 +876,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   * This function is used for 32 bit kernels.
>   *
>   * Parameters:
> - *  fd: file descriptor of the kernel to load
> + *  f: kernel file to load
>   *  elf: ELF header of the kernel
>   *  marks: array to store the offsets of various kernel structures
>   *      (start, bss, etc)
> @@ -887,7 +888,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   *  1 if unsuccessful
>   */
>  static int
> -elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
> +elf32_exec(struct bootimage *f, Elf32_Ehdr *elf, u_long *marks, int flags)
>  {
>   Elf32_Shdr *shp;
>   Elf32_Phdr *phdr;
> @@ -902,12 +903,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>   sz = elf->e_phnum * sizeof(Elf32_Phdr);
>   phdr = malloc(sz);
>
> - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> + if (f->ops->seek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
>
> - if (fread(phdr, 1, sz, fp) != sz) {
> + if (f->ops->read(f, phdr, sz) != sz) {
>   free(phdr);
>   return 1;
>   }
> @@ -947,12 +948,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
>
>   /* Read in segment. */
> - if (fseeko(fp, (off_t)phdr[i].p_offset,
> + if (f->ops->seek(f, (off_t)phdr[i].p_offset,
>      SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
> - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
>      phdr[i].p_filesz) {
>   free(phdr);
>   return 1;
> @@ -992,14 +993,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>   maxp += sizeof(Elf32_Ehdr);
>
>   if (flags & (LOAD_SYM | COUNT_SYM)) {
> - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> + if (f->ops->seek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
>   warn("lseek section headers");
>   return 1;
>   }
>   sz = elf->e_shnum * sizeof(Elf32_Shdr);
>   shp = malloc(sz);
>
> - if (fread(shp, 1, sz, fp) != sz) {
> + if (f->ops->read(f, shp, sz) != sz) {
>   free(shp);
>   return 1;
>   }
> @@ -1009,13 +1010,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>
>   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
>   char *shstr = malloc(shstrsz);
> - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> + if (f->ops->seek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> + if (f->ops->read(f, shstr, shstrsz) != shstrsz) {
>   free(shstr);
>   free(shp);
>   return 1;
> @@ -1037,13 +1038,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>      shp[i].sh_type == SHT_STRTAB ||
>      !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
>   if (havesyms && (flags & LOAD_SYM)) {
> - if (fseeko(fp, (off_t)shp[i].sh_offset,
> + if (f->ops->seek(f,
> +    (off_t)shp[i].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (mread(fp, maxp,
> + if (mread(f, maxp,
>      shp[i].sh_size) != shp[i].sh_size) {
>   free(shstr);
>   free(shp);
> blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
> file + usr.sbin/vmd/vm.c
> --- usr.sbin/vmd/vm.c
> +++ usr.sbin/vmd/vm.c
> @@ -84,7 +84,7 @@ void vcpu_exit_inout(struct vm_run_params *);
>  int vcpu_exit_eptviolation(struct vm_run_params *);
>  uint8_t vcpu_exit_pci(struct vm_run_params *);
>  int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
> -int loadfile_bios(FILE *, struct vcpu_reg_state *);
> +int loadfile_bios(struct bootimage *, struct vcpu_reg_state *);
>  int send_vm(int, struct vm_create_params *);
>  int dump_send_header(int);
>  int dump_vmr(int , struct vm_mem_range *);
> @@ -212,7 +212,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
>   * directly into memory.
>   *
>   * Parameters:
> - *  fp: file of a kernel file to load
> + *  f: BIOS file to load
>   *  (out) vrs: register state to set on init for this kernel
>   *
>   * Return values:
> @@ -220,7 +220,7 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
>   *  various error codes returned from read(2) or loadelf functions
>   */
>  int
> -loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
> +loadfile_bios(struct bootimage *f, struct vcpu_reg_state *vrs)
>  {
>   off_t size, off;
>
> @@ -228,8 +228,10 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
>   memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
>
>   /* Get the size of the BIOS image and seek to the beginning */
> - if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
> -    fseeko(fp, 0, SEEK_SET) == -1)
> + if (f->type != FILE_STREAM)
> + return (-1); /* XXX: we don't wrap gztell */
> + if (f->ops->seek(f, 0, SEEK_END) == -1 || (size = ftello(f->f)) == -1 ||
> +    f->ops->seek(f, 0, SEEK_SET) == -1)
>   return (-1);
>
>   /* The BIOS image must end at 1M */
> @@ -237,7 +239,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
>   return (-1);
>
>   /* Read BIOS image into memory */
> - if (mread(fp, off, size) != (size_t)size) {
> + if (mread(f, off, size) != (size_t)size) {
>   errno = EIO;
>   return (-1);
>   }
> @@ -277,7 +279,7 @@ start_vm(struct vmd_vm *vm, int fd)
>   struct vcpu_reg_state vrs;
>   int nicfds[VMM_MAX_NICS_PER_VM];
>   int ret;
> - FILE *fp;
> + struct bootimage *f;
>   struct vmboot_params vmboot;
>   size_t i;
>   struct vm_rwregs_params  vrp;
> @@ -332,13 +334,13 @@ start_vm(struct vmd_vm *vm, int fd)
>   memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
>
>   /* Find and open kernel image */
> - if ((fp = vmboot_open(vm->vm_kernel,
> + if ((f = vmboot_open(vm->vm_kernel,
>      vm->vm_disks[0], vmc->vmc_diskbases[0],
>      vmc->vmc_disktypes[0], &vmboot)) == NULL)
>   fatalx("failed to open kernel - exiting");
>
>   /* Load kernel image */
> - ret = loadfile_elf(fp, vcp, &vrs,
> + ret = loadfile_elf(f, vcp, &vrs,
>      vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
>
>   /*
> @@ -346,12 +348,12 @@ start_vm(struct vmd_vm *vm, int fd)
>   * with vm->vm_kernel and not loaded from the disk)
>   */
>   if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
> - ret = loadfile_bios(fp, &vrs);
> + ret = loadfile_bios(f, &vrs);
>
>   if (ret)
>   fatal("failed to load kernel or BIOS - exiting");
>
> - vmboot_close(fp, &vmboot);
> + vmboot_close(f, &vmboot);
>   }
>
>   if (vm->vm_kernel != -1)
> blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
> file + usr.sbin/vmd/vmboot.c
> --- usr.sbin/vmd/vmboot.c
> +++ usr.sbin/vmd/vmboot.c
> @@ -32,6 +32,7 @@
>  #include <fcntl.h>
>  #include <err.h>
>  #include <vis.h>
> +#include <zlib.h>
>
>  #include "vmd.h"
>  #include "vmboot.h"
> @@ -46,6 +47,9 @@ int vmboot_strategy(void *, int, daddr_t, size_t, voi
>  off_t vmboot_findopenbsd(struct open_file *, off_t, struct disklabel *);
>  void *vmboot_loadfile(struct open_file *, char *, size_t *);
>
> +static struct bootimage *vmboot_fdopen(int);
> +static struct bootimage *wrap_stream(FILE *);
> +
>  int
>  vmboot_bootcmd(char *line, struct vmboot_params *bp)
>  {
> @@ -384,7 +388,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
>   return (p);
>  }
>
> -FILE *
> +struct bootimage *
>  vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
>      struct vmboot_params *vmboot)
>  {
> @@ -392,6 +396,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
>   char *buf = NULL;
>   size_t size;
>   FILE *fp = NULL;
> + struct bootimage *f = NULL;
>   struct disklabel dl;
>   struct virtio_backing *vfp;
>   off_t sz;
> @@ -402,7 +407,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
>
>   /* First open kernel directly if specified by fd */
>   if (kernel_fd != -1)
> - return (fdopen(kernel_fd, "r"));
> + return (vmboot_fdopen(kernel_fd));
>
>   if (disk_fd == NULL || nfd < 1)
>   return (NULL);
> @@ -481,21 +486,127 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
>      vmboot->vbp_device, vmboot->vbp_image);
>   }
>
> - return (fp);
> + if ((f = wrap_stream(fp)) == NULL)
> + goto fail;
> +
> + return (f);
>    fail:
> - vmboot_close(fp, vmboot);
> + vmboot_close(f, vmboot);
>   return (NULL);
>  }
>
>  void
> -vmboot_close(FILE *fp, struct vmboot_params *vmboot)
> +vmboot_close(struct bootimage *f, struct vmboot_params *vmboot)
>  {
>   struct virtio_backing *vfp = vmboot->vbp_arg;
>
> - if (fp != NULL)
> - fclose(fp);
> + switch (f->type) {
> + case FILE_STREAM:
> + fclose(f->f);
> + break;
> + case FILE_GZIP:
> + gzclose(f->gzf);
> + break;
> + default:
> + /* can't happen */
> + errx(2, "invalid file type");
> + }
> +
>   if (vfp != NULL)
>   vfp->close(vfp->p, 1);
> + free(f);
>   free(vmboot->vbp_arg);
>   free(vmboot->vbp_buf);
>  }
> +
> +size_t
> +stream_read(struct bootimage *f, void *ptr, size_t nbytes)
> +{
> + if (f->type != FILE_STREAM)
> + return (0);
> + return (fread(ptr, 1, nbytes, f->f));
> +}
> +
> +int
> +stream_seek(struct bootimage *f, off_t offset, int whence)
> +{
> + if (f->type != FILE_STREAM)
> + return (-1); /* XXX set errno? */
> + return (fseeko(f->f, offset, whence));
> +}
> +
> +
> +size_t
> +gzip_read(struct bootimage *f, void *ptr, size_t nbytes)
> +{
> + if (f->type != FILE_GZIP)
> + return (0); /* XXX set errno? */
> + return ((ssize_t)gzread(f->gzf, ptr, nbytes));
> +}
> +
> +int
> +gzip_seek(struct bootimage *f, off_t offset, int whence)
> +{
> + if (f->type != FILE_GZIP)
> + return (-1); /* XXX set errno? */
> + return ((int)gzseek(f->gzf, offset, whence));
> +}
> +
> +static const struct bootimage_ops stream_ops = {
> + stream_read,
> + stream_seek,
> +};
> +static const struct bootimage_ops gzip_ops = {
> + gzip_read,
> + gzip_seek,
> +};
> +
> +static const u_char gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
> +
> +static struct bootimage *
> +vmboot_fdopen(int fd)
> +{
> + struct bootimage *f;
> + struct stat sb;
> + u_char magic[2];
> +
> + if (fstat(fd, &sb) == -1)
> + return (NULL);
> + if (S_ISDIR(sb.st_mode)) {
> + errno = EISDIR;
> + return (NULL);
> + }
> +
> + if ((f = calloc(1, sizeof *f)) == NULL)
> + return (NULL);
> +
> + if (pread(fd, magic, sizeof(magic), 0) != 2)
> + return NULL;
> + if (magic[0] == gz_magic[0] && magic[1] == gz_magic[1]) {
> + f->type = FILE_GZIP;
> + f->ops = &gzip_ops;
> + if ((f->gzf = gzdopen(fd, "r")) != NULL)
> + return f;
> + } else {
> + f->type = FILE_STREAM;
> + f->ops = &stream_ops;
> + if ((f->f = fdopen(fd, "r")) != NULL)
> + return f;
> + }
> +
> + free(f);
> + return NULL;
> +}
> +
> +static struct bootimage *
> +wrap_stream(FILE *fp)
> +{
> + struct bootimage *f;
> +
> + if ((f = calloc(1, sizeof *f)) == NULL)
> + return (NULL);
> + f->type = FILE_STREAM;
> + f->ops = &stream_ops;
> + f->f = fp;
> + return (f);
> +}
> blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
> file + usr.sbin/vmd/vmd.h
> --- usr.sbin/vmd/vmd.h
> +++ usr.sbin/vmd/vmd.h
> @@ -30,6 +30,7 @@
>  #include <limits.h>
>  #include <stdio.h>
>  #include <pthread.h>
> +#include <zlib.h>
>
>  #include "proc.h"
>
> @@ -475,9 +476,31 @@ int config_getif(struct privsep *, struct imsg *);
>  int config_getcdrom(struct privsep *, struct imsg *);
>
>  /* vmboot.c */
> -FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
> -void vmboot_close(FILE *, struct vmboot_params *);
> +struct bootimage_ops;
>
> +struct bootimage {
> + int type;
> +#define FILE_STREAM 0
> +#define FILE_GZIP 1
> + FILE *f;
> + gzFile *gzf;
> + struct bootimage_ops const *ops;
> +};
> +
> +struct bootimage_ops {
> + size_t (*read)(struct bootimage *, void *, size_t);
> + int (*seek)(struct bootimage *, off_t, int);
> +};
> +
> +size_t stream_read(struct bootimage *f, void *, size_t);
> +int stream_seek(struct bootimage *, off_t, int);
> +size_t gzip_read(struct bootimage *f, void *, size_t);
> +int gzip_seek(struct bootimage *, off_t, int);
> +
> +struct bootimage *vmboot_open(int, int *, int, unsigned int,
> +    struct vmboot_params *);
> +void vmboot_close(struct bootimage *, struct vmboot_params *);
> +
>  /* parse.y */
>  int parse_config(const char *);
>  int cmdline_symset(char *);


--
-Dave Voutila

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Josh Rickmar
On Wed, Mar 10, 2021 at 04:56:03PM -0500, Dave Voutila wrote:

>
> Josh Rickmar writes:
>
> > On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote:
> >> On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
> >> > On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
> >> > > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> >> > > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> >> > > > > >Synopsis: vmm/vmd fails to boot bsd.rd
> >> > > > > >Category: vmm
> >> > > > > >Environment:
> >> > > > > System      : OpenBSD 6.9
> >> > > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> >> > > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> >> > > > >
> >> > > > > Architecture: OpenBSD.amd64
> >> > > > > Machine     : amd64
> >> > > > > >Description:
> >> > > > >
> >> > > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> >> > > > > is able to be booted in this manner.
> >> > > > This is most likely due to the recent switch to compressed bsd.rd;
> >> > > > dry a gzcat(1)ed copy of bsd.rd instead.
> >> > >
> >> > > Ah, yes this works.
> >> > >
> >> > > Is this expected behavior or should vmd be taught how to read the
> >> > > compressed kernel?
> >> > >
> >> >
> >> > Sure. A diff would be welcome (libz is already in the tree and ready to use for
> >> > this).
> >>
> >> I expect this may need some cleanup, but with this patch I am able to
> >> boot the compressed bsd.rd.
> >>
> >> It replaces passing the kernel image around as a FILE* to a wrapper
> >> struct that may represent either a FILE* or gzFile.  The struct points
> >> to a function pointer to dispatch to the correct read or seek
> >> functions.
> >>
> >> This isn't wrapping gztell, which is used to discover the size of the
> >> bios firmware image, and so that will continue to error if you try to
> >> load a compressed bios.  I don't think we would want to wrap that,
> >> since seeking to the end to discover the size would result in
> >> decompressing everything twice.
> >
> > Hmm, let's rename "stdio" to "stream" for the regular uncompressed
> > files.  Otherwise this diff is the same as before.
>
> I believe you can simplify this and assume the file is gzip compressed
> and wrap the file descriptor with a call to gzdopen(3) to create a
> gzFile. The gz{read,write,tell,etc.}(3) calls should operate on both
> gzip compressed and non-compressed files (in "transparent mode").
>
> That's at least my experience using gzdopen(3) and gzread(3).

Thanks for the tip, I missed that transparent mode existed. Here's an
updated diff.  I've tested this booting OpenBSD/amd64 both from
compressed and uncompressed kernels, and booting OpenBSD and Linux
from a disk installation and BIOS, but there are some problems
introduced by this approach.

I am sure that the codepath in vmboot_open where an OpenBSD kernel is
found in a disk image is not correct anymore.  fmemopen creates a
FILE* with no file descriptor for fileno to return for gzdopen, but we
want to return a gzFile.  I wasn't able to hit this codepath while
testing though; kernel_fd was never -1 even with vmctl start -B disk.

This also still does not support compressed BIOS images (if we care),
since gzseek does not work with SEEK_END.  So instead, the image size
is being discovered using fstat(2) and only when the file was opened
in transparent mode.

diff refs/heads/master refs/heads/vmd-gzip
blob - 1770ac337a9996c76fb09de6f04909b3bb890658
blob + 49e2771d7e1a27a44d9deccbb7cc8830b0ed4544
--- usr.sbin/vmd/Makefile
+++ usr.sbin/vmd/Makefile
@@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 CFLAGS+= -Wsign-compare
 
-LDADD+= -lutil -lpthread -levent
+LDADD+= -lutil -lpthread -levent -lz
 DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
 
 YFLAGS=
blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
blob + 578d046d5e1bcd176cb59d7fddd72ba967928691
--- usr.sbin/vmd/loadfile.h
+++ usr.sbin/vmd/loadfile.h
@@ -30,6 +30,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <zlib.h>
+
 /*
  * Array indices in the u_long position array
  */
@@ -73,8 +75,8 @@
 #define PML2_PAGE 0x13000
 #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
 
-int loadfile_elf(FILE *, struct vm_create_params *,
+int loadfile_elf(gzFile, struct vm_create_params *,
     struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
 
-size_t mread(FILE *, paddr_t, size_t);
+size_t mread(gzFile, paddr_t, size_t);
 
blob - 116094260948b50b9f1eda63d3241b77bfddb39d
blob + 1fddcfe38bedea79933febe581b7c0e3cc053327
--- usr.sbin/vmd/loadfile_elf.c
+++ usr.sbin/vmd/loadfile_elf.c
@@ -115,8 +115,8 @@ union {
 
 static void setsegment(struct mem_segment_descriptor *, uint32_t,
     size_t, int, int, int, int);
-static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
-static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
+static int elf32_exec(gzFile, Elf32_Ehdr *, u_long *, int);
+static int elf64_exec(gzFile, 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, bios_bootmac_t *);
 static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
@@ -252,7 +252,7 @@ push_pt_64(void)
  * The kernel is loaded to its defined start point as set in the ELF header.
  *
  * Parameters:
- *  fp: file of a kernel file to load
+ *  f: file of a kernel file to load
  *  vcp: the VM create parameters, holding the exact memory map
  *  (out) vrs: register state to set on init for this kernel
  *  bootdev: the optional non-default boot device
@@ -263,7 +263,7 @@ push_pt_64(void)
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_elf(FILE *fp, struct vm_create_params *vcp,
+loadfile_elf(gzFile f, struct vm_create_params *vcp,
     struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
     unsigned int bootdevice)
 {
@@ -274,17 +274,18 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
  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))
+ if ((r = gzread(f, &hdr, sizeof(hdr))) == -1 || (size_t)r !=
+    sizeof(hdr))
  return 1;
 
  memset(&marks, 0, sizeof(marks));
  if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
- r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
+ r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
  is_i386 = 1;
  } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
     hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
- r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
+ r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
  } else
  errno = ENOEXEC;
 
@@ -490,7 +491,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  * into the guest address space at paddr 'addr'.
  *
  * Parameters:
- *  fd: file descriptor of the kernel image file to read from.
+ *  f: kernel image file to read from.
  *  addr: guest paddr_t to load to
  *  sz: number of bytes to load
  *
@@ -498,10 +499,11 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
  *  returns 'sz' if successful, or 0 otherwise.
  */
 size_t
-mread(FILE *fp, paddr_t addr, size_t sz)
+mread(gzFile f, paddr_t addr, size_t sz)
 {
  size_t ct;
  size_t i, rd, osz;
+ int r;
  char buf[PAGE_SIZE];
 
  /*
@@ -518,7 +520,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = sz;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -542,7 +544,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
  else
  ct = PAGE_SIZE;
 
- if (fread(buf, 1, ct, fp) != ct) {
+ if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
  log_warn("%s: error %d in mread", __progname, errno);
  return (0);
  }
@@ -665,12 +667,12 @@ mbcopy(void *src, paddr_t dst, int sz)
  *  1 if unsuccessful
  */
 static int
-elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
+elf64_exec(gzFile f, Elf64_Ehdr *elf, u_long *marks, int flags)
 {
  Elf64_Shdr *shp;
  Elf64_Phdr *phdr;
  Elf64_Off off;
- int i;
+ int i, r;
  size_t sz;
  int first;
  int havesyms;
@@ -680,12 +682,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf64_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
  free(phdr);
  return 1;
  }
@@ -725,12 +727,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (gzseek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -770,14 +772,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf64_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf64_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
  free(shp);
  return 1;
  }
@@ -787,13 +789,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
+    shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -816,13 +819,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
     !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
     !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (gzseek(f, (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
@@ -875,7 +878,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  * This function is used for 32 bit kernels.
  *
  * Parameters:
- *  fd: file descriptor of the kernel to load
+ *  f: kernel file to load
  *  elf: ELF header of the kernel
  *  marks: array to store the offsets of various kernel structures
  *      (start, bss, etc)
@@ -887,12 +890,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
  *  1 if unsuccessful
  */
 static int
-elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
+elf32_exec(gzFile f, Elf32_Ehdr *elf, u_long *marks, int flags)
 {
  Elf32_Shdr *shp;
  Elf32_Phdr *phdr;
  Elf32_Off off;
- int i;
+ int i, r;
  size_t sz;
  int first;
  int havesyms;
@@ -902,12 +905,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  sz = elf->e_phnum * sizeof(Elf32_Phdr);
  phdr = malloc(sz);
 
- if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
+ if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
 
- if (fread(phdr, 1, sz, fp) != sz) {
+ if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
  free(phdr);
  return 1;
  }
@@ -947,12 +950,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
 
  /* Read in segment. */
- if (fseeko(fp, (off_t)phdr[i].p_offset,
+ if (gzseek(f, (off_t)phdr[i].p_offset,
     SEEK_SET) == -1) {
  free(phdr);
  return 1;
  }
- if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
+ if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
     phdr[i].p_filesz) {
  free(phdr);
  return 1;
@@ -992,14 +995,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
  maxp += sizeof(Elf32_Ehdr);
 
  if (flags & (LOAD_SYM | COUNT_SYM)) {
- if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
+ if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
  warn("lseek section headers");
  return 1;
  }
  sz = elf->e_shnum * sizeof(Elf32_Shdr);
  shp = malloc(sz);
 
- if (fread(shp, 1, sz, fp) != sz) {
+ if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
  free(shp);
  return 1;
  }
@@ -1009,13 +1012,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
 
  size_t shstrsz = shp[elf->e_shstrndx].sh_size;
  char *shstr = malloc(shstrsz);
- if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
+ if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
+ if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
+    shstrsz) {
  free(shstr);
  free(shp);
  return 1;
@@ -1037,13 +1041,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
     shp[i].sh_type == SHT_STRTAB ||
     !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
  if (havesyms && (flags & LOAD_SYM)) {
- if (fseeko(fp, (off_t)shp[i].sh_offset,
+ if (gzseek(f, (off_t)shp[i].sh_offset,
     SEEK_SET) == -1) {
  free(shstr);
  free(shp);
  return 1;
  }
- if (mread(fp, maxp,
+ if (mread(f, maxp,
     shp[i].sh_size) != shp[i].sh_size) {
  free(shstr);
  free(shp);
blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
blob + 9afd81b28fc9bfc617fac7d99eb4fe744e906832
--- usr.sbin/vmd/vm.c
+++ usr.sbin/vmd/vm.c
@@ -21,6 +21,7 @@
 #include <sys/queue.h>
 #include <sys/wait.h>
 #include <sys/uio.h>
+#include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/mman.h>
@@ -84,7 +85,7 @@ void vcpu_exit_inout(struct vm_run_params *);
 int vcpu_exit_eptviolation(struct vm_run_params *);
 uint8_t vcpu_exit_pci(struct vm_run_params *);
 int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
-int loadfile_bios(FILE *, struct vcpu_reg_state *);
+int loadfile_bios(gzFile, off_t, struct vcpu_reg_state *);
 int send_vm(int, struct vm_create_params *);
 int dump_send_header(int);
 int dump_vmr(int , struct vm_mem_range *);
@@ -212,7 +213,8 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  * directly into memory.
  *
  * Parameters:
- *  fp: file of a kernel file to load
+ *  f: BIOS file to load
+ *  size: size of the image
  *  (out) vrs: register state to set on init for this kernel
  *
  * Return values:
@@ -220,16 +222,15 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
  *  various error codes returned from read(2) or loadelf functions
  */
 int
-loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
+loadfile_bios(gzFile f, off_t size, struct vcpu_reg_state *vrs)
 {
- off_t size, off;
+ off_t off;
 
  /* Set up a "flat 16 bit" register state for BIOS */
  memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
 
- /* Get the size of the BIOS image and seek to the beginning */
- if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
-    fseeko(fp, 0, SEEK_SET) == -1)
+ /* Seek to the beginning of the BIOS image */
+ if (gzseek(f, 0, SEEK_SET) == -1)
  return (-1);
 
  /* The BIOS image must end at 1M */
@@ -237,7 +238,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
  return (-1);
 
  /* Read BIOS image into memory */
- if (mread(fp, off, size) != (size_t)size) {
+ if (mread(f, off, size) != (size_t)size) {
  errno = EIO;
  return (-1);
  }
@@ -277,10 +278,11 @@ start_vm(struct vmd_vm *vm, int fd)
  struct vcpu_reg_state vrs;
  int nicfds[VMM_MAX_NICS_PER_VM];
  int ret;
- FILE *fp;
+ gzFile f;
  struct vmboot_params vmboot;
  size_t i;
  struct vm_rwregs_params  vrp;
+ struct stat sb;
 
  /* Child */
  setproctitle("%s", vcp->vcp_name);
@@ -332,26 +334,29 @@ start_vm(struct vmd_vm *vm, int fd)
  memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
 
  /* Find and open kernel image */
- if ((fp = vmboot_open(vm->vm_kernel,
+ if ((f = vmboot_open(vm->vm_kernel,
     vm->vm_disks[0], vmc->vmc_diskbases[0],
     vmc->vmc_disktypes[0], &vmboot)) == NULL)
  fatalx("failed to open kernel - exiting");
 
  /* Load kernel image */
- ret = loadfile_elf(fp, vcp, &vrs,
+ ret = loadfile_elf(f, vcp, &vrs,
     vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
 
  /*
  * Try BIOS as a fallback (only if it was provided as an image
- * with vm->vm_kernel and not loaded from the disk)
+ * with vm->vm_kernel, was not loaded from the disk, and is
+ * not gzipped)
  */
- if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
- ret = loadfile_bios(fp, &vrs);
+ if (ret && errno == ENOEXEC && vm->vm_kernel != -1 &&
+    gzdirect(f) && (ret = fstat(vm->vm_kernel, &sb)) == 0) {
+ ret = loadfile_bios(f, sb.st_size, &vrs);
+ }
 
  if (ret)
  fatal("failed to load kernel or BIOS - exiting");
 
- vmboot_close(fp, &vmboot);
+ vmboot_close(f, &vmboot);
  }
 
  if (vm->vm_kernel != -1)
blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
blob + 611b1afc99bdba1dd2a94eb4be99496374a9ad91
--- usr.sbin/vmd/vmboot.c
+++ usr.sbin/vmd/vmboot.c
@@ -32,6 +32,7 @@
 #include <fcntl.h>
 #include <err.h>
 #include <vis.h>
+#include <zlib.h>
 
 #include "vmd.h"
 #include "vmboot.h"
@@ -384,7 +385,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
  return (p);
 }
 
-FILE *
+gzFile
 vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
     struct vmboot_params *vmboot)
 {
@@ -402,7 +403,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
 
  /* First open kernel directly if specified by fd */
  if (kernel_fd != -1)
- return (fdopen(kernel_fd, "r"));
+ return (gzdopen(kernel_fd, "r"));
 
  if (disk_fd == NULL || nfd < 1)
  return (NULL);
@@ -481,19 +482,19 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
     vmboot->vbp_device, vmboot->vbp_image);
  }
 
- return (fp);
+ return (gzdopen(fileno(fp), "r"));
   fail:
- vmboot_close(fp, vmboot);
+ vmboot_close(NULL, vmboot);
  return (NULL);
 }
 
 void
-vmboot_close(FILE *fp, struct vmboot_params *vmboot)
+vmboot_close(gzFile f, struct vmboot_params *vmboot)
 {
  struct virtio_backing *vfp = vmboot->vbp_arg;
 
- if (fp != NULL)
- fclose(fp);
+ if (f != NULL)
+ gzclose(f);
  if (vfp != NULL)
  vfp->close(vfp->p, 1);
  free(vmboot->vbp_arg);
blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
blob + 843293bc7284fe4e623526c4049a7be5b9a37541
--- usr.sbin/vmd/vmd.h
+++ usr.sbin/vmd/vmd.h
@@ -30,6 +30,7 @@
 #include <limits.h>
 #include <stdio.h>
 #include <pthread.h>
+#include <zlib.h>
 
 #include "proc.h"
 
@@ -475,8 +476,8 @@ int config_getif(struct privsep *, struct imsg *);
 int config_getcdrom(struct privsep *, struct imsg *);
 
 /* vmboot.c */
-FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
-void vmboot_close(FILE *, struct vmboot_params *);
+gzFile vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
+void vmboot_close(gzFile, struct vmboot_params *);
 
 /* parse.y */
 int parse_config(const char *);

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Dave Voutila-2

Josh Rickmar writes:

> On Wed, Mar 10, 2021 at 04:56:03PM -0500, Dave Voutila wrote:
>>
>> Josh Rickmar writes:
>>
>> > On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote:
>> >> On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
>> >> > On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
>> >> > > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
>> >> > > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
>> >> > > > > >Synopsis: vmm/vmd fails to boot bsd.rd
>> >> > > > > >Category: vmm
>> >> > > > > >Environment:
>> >> > > > > System      : OpenBSD 6.9
>> >> > > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
>> >> > > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
>> >> > > > >
>> >> > > > > Architecture: OpenBSD.amd64
>> >> > > > > Machine     : amd64
>> >> > > > > >Description:
>> >> > > > >
>> >> > > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
>> >> > > > > is able to be booted in this manner.
>> >> > > > This is most likely due to the recent switch to compressed bsd.rd;
>> >> > > > dry a gzcat(1)ed copy of bsd.rd instead.
>> >> > >
>> >> > > Ah, yes this works.
>> >> > >
>> >> > > Is this expected behavior or should vmd be taught how to read the
>> >> > > compressed kernel?
>> >> > >
>> >> >
>> >> > Sure. A diff would be welcome (libz is already in the tree and ready to use for
>> >> > this).
>> >>
>> >> I expect this may need some cleanup, but with this patch I am able to
>> >> boot the compressed bsd.rd.
>> >>
>> >> It replaces passing the kernel image around as a FILE* to a wrapper
>> >> struct that may represent either a FILE* or gzFile.  The struct points
>> >> to a function pointer to dispatch to the correct read or seek
>> >> functions.
>> >>
>> >> This isn't wrapping gztell, which is used to discover the size of the
>> >> bios firmware image, and so that will continue to error if you try to
>> >> load a compressed bios.  I don't think we would want to wrap that,
>> >> since seeking to the end to discover the size would result in
>> >> decompressing everything twice.
>> >
>> > Hmm, let's rename "stdio" to "stream" for the regular uncompressed
>> > files.  Otherwise this diff is the same as before.
>>
>> I believe you can simplify this and assume the file is gzip compressed
>> and wrap the file descriptor with a call to gzdopen(3) to create a
>> gzFile. The gz{read,write,tell,etc.}(3) calls should operate on both
>> gzip compressed and non-compressed files (in "transparent mode").
>>
>> That's at least my experience using gzdopen(3) and gzread(3).
>
> Thanks for the tip, I missed that transparent mode existed. Here's an
> updated diff.  I've tested this booting OpenBSD/amd64 both from
> compressed and uncompressed kernels, and booting OpenBSD and Linux
> from a disk installation and BIOS, but there are some problems
> introduced by this approach.
>
> I am sure that the codepath in vmboot_open where an OpenBSD kernel is
> found in a disk image is not correct anymore.  fmemopen creates a
> FILE* with no file descriptor for fileno to return for gzdopen, but we
> want to return a gzFile.  I wasn't able to hit this codepath while
> testing though; kernel_fd was never -1 even with vmctl start -B disk.

mlarkin: Is the ability to extract a boot.conf and kernel image from a
UFS disk image needed anymore? I dug up the commit from 4 years ago (26
Nov 2016) and I believe it predates booting with seabios being the
default.

The commit message from reyk@:

---
Implement basic support for boot.conf(8) on the disk image.

Like the real boot loader, load and parse hd0a:/etc/boot.conf from the
first disk and fall back to /bsd.  Not all boot loader options are
supported, but it at least does set device, set image, and boot -acds
(eg. for booting single-user).

For example, it can now boot install60.fs that includes a boot.conf
with "set image /6.0/amd64/bsd.rd":
        vmctl start install -c -d install60.fs -d OpenBSD.img

This pseudo-bootloader is only needed without BIOS and could
potentially be replaced in the future.

OK mlarkin@
---

What reyk@ was doing isn't possible anymore as vmd(8) by default will
try to load the bios from /etc/firmware/vmm-bios before trying to boot
from the provided disk image. If that's the case, Josh can simplify his
diff and we can potentially remove the ufs handling logic and file(s)
from vmd(8).

Happy to take this off bugs@ in a side discussion via email.

>
> This also still does not support compressed BIOS images (if we care),
> since gzseek does not work with SEEK_END.  So instead, the image size
> is being discovered using fstat(2) and only when the file was opened
> in transparent mode.
>

AFAIK, seabios is not built compressed so this shouldn't be a problem.

> diff refs/heads/master refs/heads/vmd-gzip
> blob - 1770ac337a9996c76fb09de6f04909b3bb890658
> blob + 49e2771d7e1a27a44d9deccbb7cc8830b0ed4544
> --- usr.sbin/vmd/Makefile
> +++ usr.sbin/vmd/Makefile
> @@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
>  CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
>  CFLAGS+= -Wsign-compare
>
> -LDADD+= -lutil -lpthread -levent
> +LDADD+= -lutil -lpthread -levent -lz
>  DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
>
>  YFLAGS=
> blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
> blob + 578d046d5e1bcd176cb59d7fddd72ba967928691
> --- usr.sbin/vmd/loadfile.h
> +++ usr.sbin/vmd/loadfile.h
> @@ -30,6 +30,8 @@
>   * POSSIBILITY OF SUCH DAMAGE.
>   */
>
> +#include <zlib.h>
> +
>  /*
>   * Array indices in the u_long position array
>   */
> @@ -73,8 +75,8 @@
>  #define PML2_PAGE 0x13000
>  #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
>
> -int loadfile_elf(FILE *, struct vm_create_params *,
> +int loadfile_elf(gzFile, struct vm_create_params *,
>      struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
>
> -size_t mread(FILE *, paddr_t, size_t);
> +size_t mread(gzFile, paddr_t, size_t);
>
> blob - 116094260948b50b9f1eda63d3241b77bfddb39d
> blob + 1fddcfe38bedea79933febe581b7c0e3cc053327
> --- usr.sbin/vmd/loadfile_elf.c
> +++ usr.sbin/vmd/loadfile_elf.c
> @@ -115,8 +115,8 @@ union {
>
>  static void setsegment(struct mem_segment_descriptor *, uint32_t,
>      size_t, int, int, int, int);
> -static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
> -static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
> +static int elf32_exec(gzFile, Elf32_Ehdr *, u_long *, int);
> +static int elf64_exec(gzFile, 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, bios_bootmac_t *);
>  static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
> @@ -252,7 +252,7 @@ push_pt_64(void)
>   * The kernel is loaded to its defined start point as set in the ELF header.
>   *
>   * Parameters:
> - *  fp: file of a kernel file to load
> + *  f: file of a kernel file to load
>   *  vcp: the VM create parameters, holding the exact memory map
>   *  (out) vrs: register state to set on init for this kernel
>   *  bootdev: the optional non-default boot device
> @@ -263,7 +263,7 @@ push_pt_64(void)
>   *  various error codes returned from read(2) or loadelf functions
>   */
>  int
> -loadfile_elf(FILE *fp, struct vm_create_params *vcp,
> +loadfile_elf(gzFile f, struct vm_create_params *vcp,
>      struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
>      unsigned int bootdevice)
>  {
> @@ -274,17 +274,18 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
>   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))
> + if ((r = gzread(f, &hdr, sizeof(hdr))) == -1 || (size_t)r !=
> +    sizeof(hdr))
>   return 1;
>
>   memset(&marks, 0, sizeof(marks));
>   if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
>      hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
> - r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
> + r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
>   is_i386 = 1;
>   } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
>      hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
> - r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
> + r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
>   } else
>   errno = ENOEXEC;
>
> @@ -490,7 +491,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
>   * into the guest address space at paddr 'addr'.
>   *
>   * Parameters:
> - *  fd: file descriptor of the kernel image file to read from.
> + *  f: kernel image file to read from.
>   *  addr: guest paddr_t to load to
>   *  sz: number of bytes to load
>   *
> @@ -498,10 +499,11 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
>   *  returns 'sz' if successful, or 0 otherwise.
>   */
>  size_t
> -mread(FILE *fp, paddr_t addr, size_t sz)
> +mread(gzFile f, paddr_t addr, size_t sz)
>  {
>   size_t ct;
>   size_t i, rd, osz;
> + int r;
>   char buf[PAGE_SIZE];
>
>   /*
> @@ -518,7 +520,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
>   else
>   ct = sz;
>
> - if (fread(buf, 1, ct, fp) != ct) {
> + if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
>   log_warn("%s: error %d in mread", __progname, errno);
>   return (0);
>   }
> @@ -542,7 +544,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
>   else
>   ct = PAGE_SIZE;
>
> - if (fread(buf, 1, ct, fp) != ct) {
> + if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
>   log_warn("%s: error %d in mread", __progname, errno);
>   return (0);
>   }
> @@ -665,12 +667,12 @@ mbcopy(void *src, paddr_t dst, int sz)
>   *  1 if unsuccessful
>   */
>  static int
> -elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
> +elf64_exec(gzFile f, Elf64_Ehdr *elf, u_long *marks, int flags)
>  {
>   Elf64_Shdr *shp;
>   Elf64_Phdr *phdr;
>   Elf64_Off off;
> - int i;
> + int i, r;
>   size_t sz;
>   int first;
>   int havesyms;
> @@ -680,12 +682,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   sz = elf->e_phnum * sizeof(Elf64_Phdr);
>   phdr = malloc(sz);
>
> - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> + if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
>   free(phdr);
>   return 1;
>   }
>
> - if (fread(phdr, 1, sz, fp) != sz) {
> + if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
>   free(phdr);
>   return 1;
>   }
> @@ -725,12 +727,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
>
>   /* Read in segment. */
> - if (fseeko(fp, (off_t)phdr[i].p_offset,
> + if (gzseek(f, (off_t)phdr[i].p_offset,
>      SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
> - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
>      phdr[i].p_filesz) {
>   free(phdr);
>   return 1;
> @@ -770,14 +772,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   maxp += sizeof(Elf64_Ehdr);
>
>   if (flags & (LOAD_SYM | COUNT_SYM)) {
> - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> + if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
>   warn("lseek section headers");
>   return 1;
>   }
>   sz = elf->e_shnum * sizeof(Elf64_Shdr);
>   shp = malloc(sz);
>
> - if (fread(shp, 1, sz, fp) != sz) {
> + if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
>   free(shp);
>   return 1;
>   }
> @@ -787,13 +789,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>
>   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
>   char *shstr = malloc(shstrsz);
> - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> + if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> + if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
> +    shstrsz) {
>   free(shstr);
>   free(shp);
>   return 1;
> @@ -816,13 +819,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>      !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
>      !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
>   if (havesyms && (flags & LOAD_SYM)) {
> - if (fseeko(fp, (off_t)shp[i].sh_offset,
> + if (gzseek(f, (off_t)shp[i].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (mread(fp, maxp,
> + if (mread(f, maxp,
>      shp[i].sh_size) != shp[i].sh_size) {
>   free(shstr);
>   free(shp);
> @@ -875,7 +878,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   * This function is used for 32 bit kernels.
>   *
>   * Parameters:
> - *  fd: file descriptor of the kernel to load
> + *  f: kernel file to load
>   *  elf: ELF header of the kernel
>   *  marks: array to store the offsets of various kernel structures
>   *      (start, bss, etc)
> @@ -887,12 +890,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
>   *  1 if unsuccessful
>   */
>  static int
> -elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
> +elf32_exec(gzFile f, Elf32_Ehdr *elf, u_long *marks, int flags)
>  {
>   Elf32_Shdr *shp;
>   Elf32_Phdr *phdr;
>   Elf32_Off off;
> - int i;
> + int i, r;
>   size_t sz;
>   int first;
>   int havesyms;
> @@ -902,12 +905,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>   sz = elf->e_phnum * sizeof(Elf32_Phdr);
>   phdr = malloc(sz);
>
> - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> + if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
>
> - if (fread(phdr, 1, sz, fp) != sz) {
> + if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
>   free(phdr);
>   return 1;
>   }
> @@ -947,12 +950,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
>
>   /* Read in segment. */
> - if (fseeko(fp, (off_t)phdr[i].p_offset,
> + if (gzseek(f, (off_t)phdr[i].p_offset,
>      SEEK_SET) == -1) {
>   free(phdr);
>   return 1;
>   }
> - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
>      phdr[i].p_filesz) {
>   free(phdr);
>   return 1;
> @@ -992,14 +995,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>   maxp += sizeof(Elf32_Ehdr);
>
>   if (flags & (LOAD_SYM | COUNT_SYM)) {
> - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> + if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
>   warn("lseek section headers");
>   return 1;
>   }
>   sz = elf->e_shnum * sizeof(Elf32_Shdr);
>   shp = malloc(sz);
>
> - if (fread(shp, 1, sz, fp) != sz) {
> + if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
>   free(shp);
>   return 1;
>   }
> @@ -1009,13 +1012,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>
>   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
>   char *shstr = malloc(shstrsz);
> - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> + if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> + if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
> +    shstrsz) {
>   free(shstr);
>   free(shp);
>   return 1;
> @@ -1037,13 +1041,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
>      shp[i].sh_type == SHT_STRTAB ||
>      !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
>   if (havesyms && (flags & LOAD_SYM)) {
> - if (fseeko(fp, (off_t)shp[i].sh_offset,
> + if (gzseek(f, (off_t)shp[i].sh_offset,
>      SEEK_SET) == -1) {
>   free(shstr);
>   free(shp);
>   return 1;
>   }
> - if (mread(fp, maxp,
> + if (mread(f, maxp,
>      shp[i].sh_size) != shp[i].sh_size) {
>   free(shstr);
>   free(shp);
> blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
> blob + 9afd81b28fc9bfc617fac7d99eb4fe744e906832
> --- usr.sbin/vmd/vm.c
> +++ usr.sbin/vmd/vm.c
> @@ -21,6 +21,7 @@
>  #include <sys/queue.h>
>  #include <sys/wait.h>
>  #include <sys/uio.h>
> +#include <sys/stat.h>
>  #include <sys/socket.h>
>  #include <sys/time.h>
>  #include <sys/mman.h>
> @@ -84,7 +85,7 @@ void vcpu_exit_inout(struct vm_run_params *);
>  int vcpu_exit_eptviolation(struct vm_run_params *);
>  uint8_t vcpu_exit_pci(struct vm_run_params *);
>  int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
> -int loadfile_bios(FILE *, struct vcpu_reg_state *);
> +int loadfile_bios(gzFile, off_t, struct vcpu_reg_state *);
>  int send_vm(int, struct vm_create_params *);
>  int dump_send_header(int);
>  int dump_vmr(int , struct vm_mem_range *);
> @@ -212,7 +213,8 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
>   * directly into memory.
>   *
>   * Parameters:
> - *  fp: file of a kernel file to load
> + *  f: BIOS file to load
> + *  size: size of the image
>   *  (out) vrs: register state to set on init for this kernel
>   *
>   * Return values:
> @@ -220,16 +222,15 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
>   *  various error codes returned from read(2) or loadelf functions
>   */
>  int
> -loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
> +loadfile_bios(gzFile f, off_t size, struct vcpu_reg_state *vrs)
>  {
> - off_t size, off;
> + off_t off;
>
>   /* Set up a "flat 16 bit" register state for BIOS */
>   memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
>
> - /* Get the size of the BIOS image and seek to the beginning */
> - if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
> -    fseeko(fp, 0, SEEK_SET) == -1)
> + /* Seek to the beginning of the BIOS image */
> + if (gzseek(f, 0, SEEK_SET) == -1)
>   return (-1);
>
>   /* The BIOS image must end at 1M */
> @@ -237,7 +238,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
>   return (-1);
>
>   /* Read BIOS image into memory */
> - if (mread(fp, off, size) != (size_t)size) {
> + if (mread(f, off, size) != (size_t)size) {
>   errno = EIO;
>   return (-1);
>   }
> @@ -277,10 +278,11 @@ start_vm(struct vmd_vm *vm, int fd)
>   struct vcpu_reg_state vrs;
>   int nicfds[VMM_MAX_NICS_PER_VM];
>   int ret;
> - FILE *fp;
> + gzFile f;
>   struct vmboot_params vmboot;
>   size_t i;
>   struct vm_rwregs_params  vrp;
> + struct stat sb;
>
>   /* Child */
>   setproctitle("%s", vcp->vcp_name);
> @@ -332,26 +334,29 @@ start_vm(struct vmd_vm *vm, int fd)
>   memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
>
>   /* Find and open kernel image */
> - if ((fp = vmboot_open(vm->vm_kernel,
> + if ((f = vmboot_open(vm->vm_kernel,
>      vm->vm_disks[0], vmc->vmc_diskbases[0],
>      vmc->vmc_disktypes[0], &vmboot)) == NULL)
>   fatalx("failed to open kernel - exiting");
>
>   /* Load kernel image */
> - ret = loadfile_elf(fp, vcp, &vrs,
> + ret = loadfile_elf(f, vcp, &vrs,
>      vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
>
>   /*
>   * Try BIOS as a fallback (only if it was provided as an image
> - * with vm->vm_kernel and not loaded from the disk)
> + * with vm->vm_kernel, was not loaded from the disk, and is
> + * not gzipped)
>   */
> - if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
> - ret = loadfile_bios(fp, &vrs);
> + if (ret && errno == ENOEXEC && vm->vm_kernel != -1 &&
> +    gzdirect(f) && (ret = fstat(vm->vm_kernel, &sb)) == 0) {
> + ret = loadfile_bios(f, sb.st_size, &vrs);
> + }
>
>   if (ret)
>   fatal("failed to load kernel or BIOS - exiting");
>
> - vmboot_close(fp, &vmboot);
> + vmboot_close(f, &vmboot);
>   }
>
>   if (vm->vm_kernel != -1)
> blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
> blob + 611b1afc99bdba1dd2a94eb4be99496374a9ad91
> --- usr.sbin/vmd/vmboot.c
> +++ usr.sbin/vmd/vmboot.c
> @@ -32,6 +32,7 @@
>  #include <fcntl.h>
>  #include <err.h>
>  #include <vis.h>
> +#include <zlib.h>
>
>  #include "vmd.h"
>  #include "vmboot.h"
> @@ -384,7 +385,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
>   return (p);
>  }
>
> -FILE *
> +gzFile
>  vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
>      struct vmboot_params *vmboot)
>  {
> @@ -402,7 +403,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
>
>   /* First open kernel directly if specified by fd */
>   if (kernel_fd != -1)
> - return (fdopen(kernel_fd, "r"));
> + return (gzdopen(kernel_fd, "r"));
>
>   if (disk_fd == NULL || nfd < 1)
>   return (NULL);
> @@ -481,19 +482,19 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
>      vmboot->vbp_device, vmboot->vbp_image);
>   }
>
> - return (fp);
> + return (gzdopen(fileno(fp), "r"));
>    fail:
> - vmboot_close(fp, vmboot);
> + vmboot_close(NULL, vmboot);
>   return (NULL);
>  }
>
>  void
> -vmboot_close(FILE *fp, struct vmboot_params *vmboot)
> +vmboot_close(gzFile f, struct vmboot_params *vmboot)
>  {
>   struct virtio_backing *vfp = vmboot->vbp_arg;
>
> - if (fp != NULL)
> - fclose(fp);
> + if (f != NULL)
> + gzclose(f);
>   if (vfp != NULL)
>   vfp->close(vfp->p, 1);
>   free(vmboot->vbp_arg);
> blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
> blob + 843293bc7284fe4e623526c4049a7be5b9a37541
> --- usr.sbin/vmd/vmd.h
> +++ usr.sbin/vmd/vmd.h
> @@ -30,6 +30,7 @@
>  #include <limits.h>
>  #include <stdio.h>
>  #include <pthread.h>
> +#include <zlib.h>
>
>  #include "proc.h"
>
> @@ -475,8 +476,8 @@ int config_getif(struct privsep *, struct imsg *);
>  int config_getcdrom(struct privsep *, struct imsg *);
>
>  /* vmboot.c */
> -FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
> -void vmboot_close(FILE *, struct vmboot_params *);
> +gzFile vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
> +void vmboot_close(gzFile, struct vmboot_params *);
>
>  /* parse.y */
>  int parse_config(const char *);


--
-Dave Voutila

Reply | Threaded
Open this post in threaded view
|

Re: vmm/vmd fails to boot bsd.rd

Theo Buehler-3
On Thu, Mar 11, 2021 at 10:32:08AM -0500, Dave Voutila wrote:

>
> Josh Rickmar writes:
>
> > On Wed, Mar 10, 2021 at 04:56:03PM -0500, Dave Voutila wrote:
> >>
> >> Josh Rickmar writes:
> >>
> >> > On Wed, Mar 10, 2021 at 01:11:30PM -0500, Josh Rickmar wrote:
> >> >> On Tue, Mar 09, 2021 at 09:36:49PM -0800, Mike Larkin wrote:
> >> >> > On Mon, Mar 08, 2021 at 05:10:27PM -0500, Josh Rickmar wrote:
> >> >> > > On Mon, Mar 08, 2021 at 11:03:10PM +0100, Klemens Nanni wrote:
> >> >> > > > On Mon, Mar 08, 2021 at 04:50:53PM -0500, Josh Rickmar wrote:
> >> >> > > > > >Synopsis: vmm/vmd fails to boot bsd.rd
> >> >> > > > > >Category: vmm
> >> >> > > > > >Environment:
> >> >> > > > > System      : OpenBSD 6.9
> >> >> > > > > Details     : OpenBSD 6.9-beta (GENERIC.MP) #385: Mon Mar  8 12:57:12 MST 2021
> >> >> > > > > [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
> >> >> > > > >
> >> >> > > > > Architecture: OpenBSD.amd64
> >> >> > > > > Machine     : amd64
> >> >> > > > > >Description:
> >> >> > > > >
> >> >> > > > > vmm/vmd fails to boot /bsd.rd from a recent snapshot, however, bsd.sp
> >> >> > > > > is able to be booted in this manner.
> >> >> > > > This is most likely due to the recent switch to compressed bsd.rd;
> >> >> > > > dry a gzcat(1)ed copy of bsd.rd instead.
> >> >> > >
> >> >> > > Ah, yes this works.
> >> >> > >
> >> >> > > Is this expected behavior or should vmd be taught how to read the
> >> >> > > compressed kernel?
> >> >> > >
> >> >> >
> >> >> > Sure. A diff would be welcome (libz is already in the tree and ready to use for
> >> >> > this).
> >> >>
> >> >> I expect this may need some cleanup, but with this patch I am able to
> >> >> boot the compressed bsd.rd.
> >> >>
> >> >> It replaces passing the kernel image around as a FILE* to a wrapper
> >> >> struct that may represent either a FILE* or gzFile.  The struct points
> >> >> to a function pointer to dispatch to the correct read or seek
> >> >> functions.
> >> >>
> >> >> This isn't wrapping gztell, which is used to discover the size of the
> >> >> bios firmware image, and so that will continue to error if you try to
> >> >> load a compressed bios.  I don't think we would want to wrap that,
> >> >> since seeking to the end to discover the size would result in
> >> >> decompressing everything twice.
> >> >
> >> > Hmm, let's rename "stdio" to "stream" for the regular uncompressed
> >> > files.  Otherwise this diff is the same as before.
> >>
> >> I believe you can simplify this and assume the file is gzip compressed
> >> and wrap the file descriptor with a call to gzdopen(3) to create a
> >> gzFile. The gz{read,write,tell,etc.}(3) calls should operate on both
> >> gzip compressed and non-compressed files (in "transparent mode").
> >>
> >> That's at least my experience using gzdopen(3) and gzread(3).
> >
> > Thanks for the tip, I missed that transparent mode existed. Here's an
> > updated diff.  I've tested this booting OpenBSD/amd64 both from
> > compressed and uncompressed kernels, and booting OpenBSD and Linux
> > from a disk installation and BIOS, but there are some problems
> > introduced by this approach.
> >
> > I am sure that the codepath in vmboot_open where an OpenBSD kernel is
> > found in a disk image is not correct anymore.  fmemopen creates a
> > FILE* with no file descriptor for fileno to return for gzdopen, but we
> > want to return a gzFile.  I wasn't able to hit this codepath while
> > testing though; kernel_fd was never -1 even with vmctl start -B disk.
>
> mlarkin: Is the ability to extract a boot.conf and kernel image from a
> UFS disk image needed anymore? I dug up the commit from 4 years ago (26
> Nov 2016) and I believe it predates booting with seabios being the
> default.
>
> The commit message from reyk@:
>
> ---
> Implement basic support for boot.conf(8) on the disk image.
>
> Like the real boot loader, load and parse hd0a:/etc/boot.conf from the
> first disk and fall back to /bsd.  Not all boot loader options are
> supported, but it at least does set device, set image, and boot -acds
> (eg. for booting single-user).
>
> For example, it can now boot install60.fs that includes a boot.conf
> with "set image /6.0/amd64/bsd.rd":
> vmctl start install -c -d install60.fs -d OpenBSD.img
>
> This pseudo-bootloader is only needed without BIOS and could
> potentially be replaced in the future.
>
> OK mlarkin@
> ---
>
> What reyk@ was doing isn't possible anymore as vmd(8) by default will
> try to load the bios from /etc/firmware/vmm-bios before trying to boot
> from the provided disk image. If that's the case, Josh can simplify his
> diff and we can potentially remove the ufs handling logic and file(s)
> from vmd(8).

It is still possible to bypass seabios using -b disk -d disk. This would
need updating to ufs2 however. I sent out a diff doing that, but got no
feedback, so I suspect I'm the only one who has been using this. FWIW I
have no objection to removing that code.

My understanding is that the only motivation for not using seabios is
the licensing.

>
> Happy to take this off bugs@ in a side discussion via email.
>
> >
> > This also still does not support compressed BIOS images (if we care),
> > since gzseek does not work with SEEK_END.  So instead, the image size
> > is being discovered using fstat(2) and only when the file was opened
> > in transparent mode.
> >
>
> AFAIK, seabios is not built compressed so this shouldn't be a problem.
>
> > diff refs/heads/master refs/heads/vmd-gzip
> > blob - 1770ac337a9996c76fb09de6f04909b3bb890658
> > blob + 49e2771d7e1a27a44d9deccbb7cc8830b0ed4544
> > --- usr.sbin/vmd/Makefile
> > +++ usr.sbin/vmd/Makefile
> > @@ -14,7 +14,7 @@ CFLAGS+= -Wmissing-declarations
> >  CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
> >  CFLAGS+= -Wsign-compare
> >
> > -LDADD+= -lutil -lpthread -levent
> > +LDADD+= -lutil -lpthread -levent -lz
> >  DPADD+= ${LIBUTIL} ${LIBPTHREAD} ${LIBEVENT}
> >
> >  YFLAGS=
> > blob - de7fd5f270dc1b900c11ed082fb0b4f94acc01b0
> > blob + 578d046d5e1bcd176cb59d7fddd72ba967928691
> > --- usr.sbin/vmd/loadfile.h
> > +++ usr.sbin/vmd/loadfile.h
> > @@ -30,6 +30,8 @@
> >   * POSSIBILITY OF SUCH DAMAGE.
> >   */
> >
> > +#include <zlib.h>
> > +
> >  /*
> >   * Array indices in the u_long position array
> >   */
> > @@ -73,8 +75,8 @@
> >  #define PML2_PAGE 0x13000
> >  #define NPTE_PG (PAGE_SIZE / sizeof(uint64_t))
> >
> > -int loadfile_elf(FILE *, struct vm_create_params *,
> > +int loadfile_elf(gzFile, struct vm_create_params *,
> >      struct vcpu_reg_state *, uint32_t, uint32_t, unsigned int);
> >
> > -size_t mread(FILE *, paddr_t, size_t);
> > +size_t mread(gzFile, paddr_t, size_t);
> >
> > blob - 116094260948b50b9f1eda63d3241b77bfddb39d
> > blob + 1fddcfe38bedea79933febe581b7c0e3cc053327
> > --- usr.sbin/vmd/loadfile_elf.c
> > +++ usr.sbin/vmd/loadfile_elf.c
> > @@ -115,8 +115,8 @@ union {
> >
> >  static void setsegment(struct mem_segment_descriptor *, uint32_t,
> >      size_t, int, int, int, int);
> > -static int elf32_exec(FILE *, Elf32_Ehdr *, u_long *, int);
> > -static int elf64_exec(FILE *, Elf64_Ehdr *, u_long *, int);
> > +static int elf32_exec(gzFile, Elf32_Ehdr *, u_long *, int);
> > +static int elf64_exec(gzFile, 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, bios_bootmac_t *);
> >  static size_t push_stack(uint32_t, uint32_t, uint32_t, uint32_t);
> > @@ -252,7 +252,7 @@ push_pt_64(void)
> >   * The kernel is loaded to its defined start point as set in the ELF header.
> >   *
> >   * Parameters:
> > - *  fp: file of a kernel file to load
> > + *  f: file of a kernel file to load
> >   *  vcp: the VM create parameters, holding the exact memory map
> >   *  (out) vrs: register state to set on init for this kernel
> >   *  bootdev: the optional non-default boot device
> > @@ -263,7 +263,7 @@ push_pt_64(void)
> >   *  various error codes returned from read(2) or loadelf functions
> >   */
> >  int
> > -loadfile_elf(FILE *fp, struct vm_create_params *vcp,
> > +loadfile_elf(gzFile f, struct vm_create_params *vcp,
> >      struct vcpu_reg_state *vrs, uint32_t bootdev, uint32_t howto,
> >      unsigned int bootdevice)
> >  {
> > @@ -274,17 +274,18 @@ loadfile_elf(FILE *fp, struct vm_create_params *vcp,
> >   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))
> > + if ((r = gzread(f, &hdr, sizeof(hdr))) == -1 || (size_t)r !=
> > +    sizeof(hdr))
> >   return 1;
> >
> >   memset(&marks, 0, sizeof(marks));
> >   if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
> >      hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
> > - r = elf32_exec(fp, &hdr.elf32, marks, LOAD_ALL);
> > + r = elf32_exec(f, &hdr.elf32, marks, LOAD_ALL);
> >   is_i386 = 1;
> >   } else if (memcmp(hdr.elf64.e_ident, ELFMAG, SELFMAG) == 0 &&
> >      hdr.elf64.e_ident[EI_CLASS] == ELFCLASS64) {
> > - r = elf64_exec(fp, &hdr.elf64, marks, LOAD_ALL);
> > + r = elf64_exec(f, &hdr.elf64, marks, LOAD_ALL);
> >   } else
> >   errno = ENOEXEC;
> >
> > @@ -490,7 +491,7 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
> >   * into the guest address space at paddr 'addr'.
> >   *
> >   * Parameters:
> > - *  fd: file descriptor of the kernel image file to read from.
> > + *  f: kernel image file to read from.
> >   *  addr: guest paddr_t to load to
> >   *  sz: number of bytes to load
> >   *
> > @@ -498,10 +499,11 @@ push_stack(uint32_t bootargsz, uint32_t end, uint32_t
> >   *  returns 'sz' if successful, or 0 otherwise.
> >   */
> >  size_t
> > -mread(FILE *fp, paddr_t addr, size_t sz)
> > +mread(gzFile f, paddr_t addr, size_t sz)
> >  {
> >   size_t ct;
> >   size_t i, rd, osz;
> > + int r;
> >   char buf[PAGE_SIZE];
> >
> >   /*
> > @@ -518,7 +520,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
> >   else
> >   ct = sz;
> >
> > - if (fread(buf, 1, ct, fp) != ct) {
> > + if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
> >   log_warn("%s: error %d in mread", __progname, errno);
> >   return (0);
> >   }
> > @@ -542,7 +544,7 @@ mread(FILE *fp, paddr_t addr, size_t sz)
> >   else
> >   ct = PAGE_SIZE;
> >
> > - if (fread(buf, 1, ct, fp) != ct) {
> > + if ((r = gzread(f, buf, ct)) == -1 || (size_t)r != ct) {
> >   log_warn("%s: error %d in mread", __progname, errno);
> >   return (0);
> >   }
> > @@ -665,12 +667,12 @@ mbcopy(void *src, paddr_t dst, int sz)
> >   *  1 if unsuccessful
> >   */
> >  static int
> > -elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, int flags)
> > +elf64_exec(gzFile f, Elf64_Ehdr *elf, u_long *marks, int flags)
> >  {
> >   Elf64_Shdr *shp;
> >   Elf64_Phdr *phdr;
> >   Elf64_Off off;
> > - int i;
> > + int i, r;
> >   size_t sz;
> >   int first;
> >   int havesyms;
> > @@ -680,12 +682,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >   sz = elf->e_phnum * sizeof(Elf64_Phdr);
> >   phdr = malloc(sz);
> >
> > - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> > + if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> >   free(phdr);
> >   return 1;
> >   }
> >
> > - if (fread(phdr, 1, sz, fp) != sz) {
> > + if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
> >   free(phdr);
> >   return 1;
> >   }
> > @@ -725,12 +727,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
> >
> >   /* Read in segment. */
> > - if (fseeko(fp, (off_t)phdr[i].p_offset,
> > + if (gzseek(f, (off_t)phdr[i].p_offset,
> >      SEEK_SET) == -1) {
> >   free(phdr);
> >   return 1;
> >   }
> > - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> > + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
> >      phdr[i].p_filesz) {
> >   free(phdr);
> >   return 1;
> > @@ -770,14 +772,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >   maxp += sizeof(Elf64_Ehdr);
> >
> >   if (flags & (LOAD_SYM | COUNT_SYM)) {
> > - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> > + if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> >   warn("lseek section headers");
> >   return 1;
> >   }
> >   sz = elf->e_shnum * sizeof(Elf64_Shdr);
> >   shp = malloc(sz);
> >
> > - if (fread(shp, 1, sz, fp) != sz) {
> > + if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
> >   free(shp);
> >   return 1;
> >   }
> > @@ -787,13 +789,14 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >
> >   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
> >   char *shstr = malloc(shstrsz);
> > - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> > + if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
> >      SEEK_SET) == -1) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> >   }
> > - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> > + if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
> > +    shstrsz) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> > @@ -816,13 +819,13 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >      !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
> >      !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
> >   if (havesyms && (flags & LOAD_SYM)) {
> > - if (fseeko(fp, (off_t)shp[i].sh_offset,
> > + if (gzseek(f, (off_t)shp[i].sh_offset,
> >      SEEK_SET) == -1) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> >   }
> > - if (mread(fp, maxp,
> > + if (mread(f, maxp,
> >      shp[i].sh_size) != shp[i].sh_size) {
> >   free(shstr);
> >   free(shp);
> > @@ -875,7 +878,7 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >   * This function is used for 32 bit kernels.
> >   *
> >   * Parameters:
> > - *  fd: file descriptor of the kernel to load
> > + *  f: kernel file to load
> >   *  elf: ELF header of the kernel
> >   *  marks: array to store the offsets of various kernel structures
> >   *      (start, bss, etc)
> > @@ -887,12 +890,12 @@ elf64_exec(FILE *fp, Elf64_Ehdr *elf, u_long *marks, i
> >   *  1 if unsuccessful
> >   */
> >  static int
> > -elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, int flags)
> > +elf32_exec(gzFile f, Elf32_Ehdr *elf, u_long *marks, int flags)
> >  {
> >   Elf32_Shdr *shp;
> >   Elf32_Phdr *phdr;
> >   Elf32_Off off;
> > - int i;
> > + int i, r;
> >   size_t sz;
> >   int first;
> >   int havesyms;
> > @@ -902,12 +905,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
> >   sz = elf->e_phnum * sizeof(Elf32_Phdr);
> >   phdr = malloc(sz);
> >
> > - if (fseeko(fp, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
> > + if (gzseek(f, (off_t)elf->e_phoff, SEEK_SET) == -1) {
> >   free(phdr);
> >   return 1;
> >   }
> >
> > - if (fread(phdr, 1, sz, fp) != sz) {
> > + if ((r = gzread(f, phdr, sz)) == -1 || (size_t)r != sz) {
> >   free(phdr);
> >   return 1;
> >   }
> > @@ -947,12 +950,12 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
> >      (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
> >
> >   /* Read in segment. */
> > - if (fseeko(fp, (off_t)phdr[i].p_offset,
> > + if (gzseek(f, (off_t)phdr[i].p_offset,
> >      SEEK_SET) == -1) {
> >   free(phdr);
> >   return 1;
> >   }
> > - if (mread(fp, phdr[i].p_paddr, phdr[i].p_filesz) !=
> > + if (mread(f, phdr[i].p_paddr, phdr[i].p_filesz) !=
> >      phdr[i].p_filesz) {
> >   free(phdr);
> >   return 1;
> > @@ -992,14 +995,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
> >   maxp += sizeof(Elf32_Ehdr);
> >
> >   if (flags & (LOAD_SYM | COUNT_SYM)) {
> > - if (fseeko(fp, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
> > + if (gzseek(f, (off_t)elf->e_shoff, SEEK_SET) == -1) {
> >   warn("lseek section headers");
> >   return 1;
> >   }
> >   sz = elf->e_shnum * sizeof(Elf32_Shdr);
> >   shp = malloc(sz);
> >
> > - if (fread(shp, 1, sz, fp) != sz) {
> > + if ((r = gzread(f, shp, sz)) == -1 || (size_t)r != sz) {
> >   free(shp);
> >   return 1;
> >   }
> > @@ -1009,13 +1012,14 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
> >
> >   size_t shstrsz = shp[elf->e_shstrndx].sh_size;
> >   char *shstr = malloc(shstrsz);
> > - if (fseeko(fp, (off_t)shp[elf->e_shstrndx].sh_offset,
> > + if (gzseek(f, (off_t)shp[elf->e_shstrndx].sh_offset,
> >      SEEK_SET) == -1) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> >   }
> > - if (fread(shstr, 1, shstrsz, fp) != shstrsz) {
> > + if ((r = gzread(f, shstr, shstrsz)) == -1 || (size_t)r !=
> > +    shstrsz) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> > @@ -1037,13 +1041,13 @@ elf32_exec(FILE *fp, Elf32_Ehdr *elf, u_long *marks, i
> >      shp[i].sh_type == SHT_STRTAB ||
> >      !strcmp(shstr + shp[i].sh_name, ".debug_line")) {
> >   if (havesyms && (flags & LOAD_SYM)) {
> > - if (fseeko(fp, (off_t)shp[i].sh_offset,
> > + if (gzseek(f, (off_t)shp[i].sh_offset,
> >      SEEK_SET) == -1) {
> >   free(shstr);
> >   free(shp);
> >   return 1;
> >   }
> > - if (mread(fp, maxp,
> > + if (mread(f, maxp,
> >      shp[i].sh_size) != shp[i].sh_size) {
> >   free(shstr);
> >   free(shp);
> > blob - e825f203ebbbb6d8c5dab5c1594dc815f92fd867
> > blob + 9afd81b28fc9bfc617fac7d99eb4fe744e906832
> > --- usr.sbin/vmd/vm.c
> > +++ usr.sbin/vmd/vm.c
> > @@ -21,6 +21,7 @@
> >  #include <sys/queue.h>
> >  #include <sys/wait.h>
> >  #include <sys/uio.h>
> > +#include <sys/stat.h>
> >  #include <sys/socket.h>
> >  #include <sys/time.h>
> >  #include <sys/mman.h>
> > @@ -84,7 +85,7 @@ void vcpu_exit_inout(struct vm_run_params *);
> >  int vcpu_exit_eptviolation(struct vm_run_params *);
> >  uint8_t vcpu_exit_pci(struct vm_run_params *);
> >  int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
> > -int loadfile_bios(FILE *, struct vcpu_reg_state *);
> > +int loadfile_bios(gzFile, off_t, struct vcpu_reg_state *);
> >  int send_vm(int, struct vm_create_params *);
> >  int dump_send_header(int);
> >  int dump_vmr(int , struct vm_mem_range *);
> > @@ -212,7 +213,8 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
> >   * directly into memory.
> >   *
> >   * Parameters:
> > - *  fp: file of a kernel file to load
> > + *  f: BIOS file to load
> > + *  size: size of the image
> >   *  (out) vrs: register state to set on init for this kernel
> >   *
> >   * Return values:
> > @@ -220,16 +222,15 @@ static const struct vcpu_reg_state vcpu_init_flat16 =
> >   *  various error codes returned from read(2) or loadelf functions
> >   */
> >  int
> > -loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
> > +loadfile_bios(gzFile f, off_t size, struct vcpu_reg_state *vrs)
> >  {
> > - off_t size, off;
> > + off_t off;
> >
> >   /* Set up a "flat 16 bit" register state for BIOS */
> >   memcpy(vrs, &vcpu_init_flat16, sizeof(*vrs));
> >
> > - /* Get the size of the BIOS image and seek to the beginning */
> > - if (fseeko(fp, 0, SEEK_END) == -1 || (size = ftello(fp)) == -1 ||
> > -    fseeko(fp, 0, SEEK_SET) == -1)
> > + /* Seek to the beginning of the BIOS image */
> > + if (gzseek(f, 0, SEEK_SET) == -1)
> >   return (-1);
> >
> >   /* The BIOS image must end at 1M */
> > @@ -237,7 +238,7 @@ loadfile_bios(FILE *fp, struct vcpu_reg_state *vrs)
> >   return (-1);
> >
> >   /* Read BIOS image into memory */
> > - if (mread(fp, off, size) != (size_t)size) {
> > + if (mread(f, off, size) != (size_t)size) {
> >   errno = EIO;
> >   return (-1);
> >   }
> > @@ -277,10 +278,11 @@ start_vm(struct vmd_vm *vm, int fd)
> >   struct vcpu_reg_state vrs;
> >   int nicfds[VMM_MAX_NICS_PER_VM];
> >   int ret;
> > - FILE *fp;
> > + gzFile f;
> >   struct vmboot_params vmboot;
> >   size_t i;
> >   struct vm_rwregs_params  vrp;
> > + struct stat sb;
> >
> >   /* Child */
> >   setproctitle("%s", vcp->vcp_name);
> > @@ -332,26 +334,29 @@ start_vm(struct vmd_vm *vm, int fd)
> >   memcpy(&vrs, &vcpu_init_flat64, sizeof(vrs));
> >
> >   /* Find and open kernel image */
> > - if ((fp = vmboot_open(vm->vm_kernel,
> > + if ((f = vmboot_open(vm->vm_kernel,
> >      vm->vm_disks[0], vmc->vmc_diskbases[0],
> >      vmc->vmc_disktypes[0], &vmboot)) == NULL)
> >   fatalx("failed to open kernel - exiting");
> >
> >   /* Load kernel image */
> > - ret = loadfile_elf(fp, vcp, &vrs,
> > + ret = loadfile_elf(f, vcp, &vrs,
> >      vmboot.vbp_bootdev, vmboot.vbp_howto, vmc->vmc_bootdevice);
> >
> >   /*
> >   * Try BIOS as a fallback (only if it was provided as an image
> > - * with vm->vm_kernel and not loaded from the disk)
> > + * with vm->vm_kernel, was not loaded from the disk, and is
> > + * not gzipped)
> >   */
> > - if (ret && errno == ENOEXEC && vm->vm_kernel != -1)
> > - ret = loadfile_bios(fp, &vrs);
> > + if (ret && errno == ENOEXEC && vm->vm_kernel != -1 &&
> > +    gzdirect(f) && (ret = fstat(vm->vm_kernel, &sb)) == 0) {
> > + ret = loadfile_bios(f, sb.st_size, &vrs);
> > + }
> >
> >   if (ret)
> >   fatal("failed to load kernel or BIOS - exiting");
> >
> > - vmboot_close(fp, &vmboot);
> > + vmboot_close(f, &vmboot);
> >   }
> >
> >   if (vm->vm_kernel != -1)
> > blob - 349635fc33db2552a87ce87a66fa5289f6b345bd
> > blob + 611b1afc99bdba1dd2a94eb4be99496374a9ad91
> > --- usr.sbin/vmd/vmboot.c
> > +++ usr.sbin/vmd/vmboot.c
> > @@ -32,6 +32,7 @@
> >  #include <fcntl.h>
> >  #include <err.h>
> >  #include <vis.h>
> > +#include <zlib.h>
> >
> >  #include "vmd.h"
> >  #include "vmboot.h"
> > @@ -384,7 +385,7 @@ vmboot_loadfile(struct open_file *f, char *file, size_
> >   return (p);
> >  }
> >
> > -FILE *
> > +gzFile
> >  vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsigned int disk_type,
> >      struct vmboot_params *vmboot)
> >  {
> > @@ -402,7 +403,7 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
> >
> >   /* First open kernel directly if specified by fd */
> >   if (kernel_fd != -1)
> > - return (fdopen(kernel_fd, "r"));
> > + return (gzdopen(kernel_fd, "r"));
> >
> >   if (disk_fd == NULL || nfd < 1)
> >   return (NULL);
> > @@ -481,19 +482,19 @@ vmboot_open(int kernel_fd, int *disk_fd, int nfd, unsi
> >      vmboot->vbp_device, vmboot->vbp_image);
> >   }
> >
> > - return (fp);
> > + return (gzdopen(fileno(fp), "r"));
> >    fail:
> > - vmboot_close(fp, vmboot);
> > + vmboot_close(NULL, vmboot);
> >   return (NULL);
> >  }
> >
> >  void
> > -vmboot_close(FILE *fp, struct vmboot_params *vmboot)
> > +vmboot_close(gzFile f, struct vmboot_params *vmboot)
> >  {
> >   struct virtio_backing *vfp = vmboot->vbp_arg;
> >
> > - if (fp != NULL)
> > - fclose(fp);
> > + if (f != NULL)
> > + gzclose(f);
> >   if (vfp != NULL)
> >   vfp->close(vfp->p, 1);
> >   free(vmboot->vbp_arg);
> > blob - 325d40d1ace0714e86d20fac20f3eaabd406d721
> > blob + 843293bc7284fe4e623526c4049a7be5b9a37541
> > --- usr.sbin/vmd/vmd.h
> > +++ usr.sbin/vmd/vmd.h
> > @@ -30,6 +30,7 @@
> >  #include <limits.h>
> >  #include <stdio.h>
> >  #include <pthread.h>
> > +#include <zlib.h>
> >
> >  #include "proc.h"
> >
> > @@ -475,8 +476,8 @@ int config_getif(struct privsep *, struct imsg *);
> >  int config_getcdrom(struct privsep *, struct imsg *);
> >
> >  /* vmboot.c */
> > -FILE *vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
> > -void vmboot_close(FILE *, struct vmboot_params *);
> > +gzFile vmboot_open(int, int *, int, unsigned int, struct vmboot_params *);
> > +void vmboot_close(gzFile, struct vmboot_params *);
> >
> >  /* parse.y */
> >  int parse_config(const char *);
>
>
> --
> -Dave Voutila
>