16800 bhyve upstream sync 2024 September
Reviewed by: Marco van Wieringen <marco.van.wieringen@planets.elm.net> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Dan McDonald <danmcd@mnx.io>
This commit is contained in:
parent
535ba94690
commit
5c4a5fe167
|
@ -482,66 +482,7 @@ usr/src/uts/sparc/nsmb/ioc_check.ref
|
|||
usr/src/cmd/bhyve/README.sync
|
||||
usr/src/cmd/bhyve/THIRDPARTYLICENSE
|
||||
usr/src/cmd/bhyve/THIRDPARTYLICENSE.descrip
|
||||
usr/src/cmd/bhyve/acpi.[ch]
|
||||
usr/src/cmd/bhyve/ahci.h
|
||||
usr/src/cmd/bhyve/atkbdc.[ch]
|
||||
usr/src/cmd/bhyve/basl.[ch]
|
||||
usr/src/cmd/bhyve/bhyvegc.[ch]
|
||||
usr/src/cmd/bhyve/bhyverun.[ch]
|
||||
usr/src/cmd/bhyve/block_if.[ch]
|
||||
usr/src/cmd/bhyve/bootrom.[ch]
|
||||
usr/src/cmd/bhyve/config.[ch]
|
||||
usr/src/cmd/bhyve/console.[ch]
|
||||
usr/src/cmd/bhyve/consport.c
|
||||
usr/src/cmd/bhyve/dbgport.[ch]
|
||||
usr/src/cmd/bhyve/e820.[ch]
|
||||
usr/src/cmd/bhyve/fwctl.[ch]
|
||||
usr/src/cmd/bhyve/gdb.[ch]
|
||||
usr/src/cmd/bhyve/hda_codec.c
|
||||
usr/src/cmd/bhyve/inout.[ch]
|
||||
usr/src/cmd/bhyve/ioapic.[ch]
|
||||
usr/src/cmd/bhyve/mem.[ch]
|
||||
usr/src/cmd/bhyve/mevent.[ch]
|
||||
usr/src/cmd/bhyve/mevent_test.c
|
||||
usr/src/cmd/bhyve/mptbl.[ch]
|
||||
usr/src/cmd/bhyve/net_backends.[ch]
|
||||
usr/src/cmd/bhyve/net_utils.[ch]
|
||||
usr/src/cmd/bhyve/pci_ahci.c
|
||||
usr/src/cmd/bhyve/pci_e82545.c
|
||||
usr/src/cmd/bhyve/pci_emul.[ch]
|
||||
usr/src/cmd/bhyve/pci_fbuf.c
|
||||
usr/src/cmd/bhyve/pci_hda.[ch]
|
||||
usr/src/cmd/bhyve/pci_hostbridge.c
|
||||
usr/src/cmd/bhyve/pci_irq.[ch]
|
||||
usr/src/cmd/bhyve/pci_lpc.[ch]
|
||||
usr/src/cmd/bhyve/pci_nvme.c
|
||||
usr/src/cmd/bhyve/pci_passthru.[ch]
|
||||
usr/src/cmd/bhyve/pci_uart.c
|
||||
usr/src/cmd/bhyve/pci_virtio_block.c
|
||||
usr/src/cmd/bhyve/pci_virtio_console.c
|
||||
usr/src/cmd/bhyve/pci_virtio_input.c
|
||||
usr/src/cmd/bhyve/pci_virtio_net.c
|
||||
usr/src/cmd/bhyve/pci_virtio_rnd.c
|
||||
usr/src/cmd/bhyve/pci_virtio_scsi.c
|
||||
usr/src/cmd/bhyve/pci_virtio_viona.c
|
||||
usr/src/cmd/bhyve/pci_xhci.[ch]
|
||||
usr/src/cmd/bhyve/pctestdev.[ch]
|
||||
usr/src/cmd/bhyve/pm.c
|
||||
usr/src/cmd/bhyve/pmtmr.c
|
||||
usr/src/cmd/bhyve/post.c
|
||||
usr/src/cmd/bhyve/ps2kbd.[ch]
|
||||
usr/src/cmd/bhyve/ps2mouse.[ch]
|
||||
usr/src/cmd/bhyve/rtc.[ch]
|
||||
usr/src/cmd/bhyve/smbiostbl.[ch]
|
||||
usr/src/cmd/bhyve/sockstream.[ch]
|
||||
usr/src/cmd/bhyve/spinup_ap.[ch]
|
||||
usr/src/cmd/bhyve/task_switch.c
|
||||
usr/src/cmd/bhyve/uart_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_mouse.c
|
||||
usr/src/cmd/bhyve/vga.[ch]
|
||||
usr/src/cmd/bhyve/virtio.[ch]
|
||||
usr/src/cmd/bhyve/xmsr.[ch]
|
||||
usr/src/cmd/bhyve/*
|
||||
usr/src/cmd/bhyvectl/THIRDPARTYLICENSE
|
||||
usr/src/cmd/bhyvectl/THIRDPARTYLICENSE.descrip
|
||||
usr/src/cmd/bhyvectl/bhyvectl.c
|
||||
|
|
|
@ -1178,78 +1178,81 @@ usr/src/uts/intel/sys/acpi/platform/acwin64.h
|
|||
|
||||
# bhyve sources
|
||||
syntax: glob
|
||||
usr/src/cmd/bhyve/acpi.[ch]
|
||||
usr/src/cmd/bhyve/acpi_device.[ch]
|
||||
usr/src/cmd/bhyve/ahci.h
|
||||
usr/src/cmd/bhyve/atkbdc.[ch]
|
||||
usr/src/cmd/bhyve/audio.[ch]
|
||||
usr/src/cmd/bhyve/basl.[ch]
|
||||
usr/src/cmd/bhyve/bhyvegc.[ch]
|
||||
usr/src/cmd/bhyve/bhyverun.[ch]
|
||||
usr/src/cmd/bhyve/block_if.[ch]
|
||||
usr/src/cmd/bhyve/bootrom.[ch]
|
||||
usr/src/cmd/bhyve/crc16.[ch]
|
||||
usr/src/cmd/bhyve/config.[ch]
|
||||
usr/src/cmd/bhyve/console.[ch]
|
||||
usr/src/cmd/bhyve/console.[ch]
|
||||
usr/src/cmd/bhyve/consport.c
|
||||
usr/src/cmd/bhyve/dbgport.[ch]
|
||||
usr/src/cmd/bhyve/debug.h
|
||||
usr/src/cmd/bhyve/e820.[ch]
|
||||
usr/src/cmd/bhyve/fwctl.[ch]
|
||||
usr/src/cmd/bhyve/gdb.[ch]
|
||||
usr/src/cmd/bhyve/hda_codec.c
|
||||
usr/src/cmd/bhyve/hda_reg.h
|
||||
usr/src/cmd/bhyve/hdac_reg.h
|
||||
usr/src/cmd/bhyve/inout.[ch]
|
||||
usr/src/cmd/bhyve/ioapic.[ch]
|
||||
usr/src/cmd/bhyve/iov.[ch]
|
||||
usr/src/cmd/bhyve/kernemu_dev.[ch]
|
||||
usr/src/cmd/bhyve/mem.[ch]
|
||||
usr/src/cmd/bhyve/mevent.[ch]
|
||||
usr/src/cmd/bhyve/mevent_test.c
|
||||
usr/src/cmd/bhyve/mptbl.[ch]
|
||||
usr/src/cmd/bhyve/net_utils.[ch]
|
||||
usr/src/cmd/bhyve/net_backends.[ch]
|
||||
usr/src/cmd/bhyve/pci_ahci.c
|
||||
usr/src/cmd/bhyve/pci_e82545.c
|
||||
usr/src/cmd/bhyve/pci_emul.[ch]
|
||||
usr/src/cmd/bhyve/pci_fbuf.c
|
||||
usr/src/cmd/bhyve/pci_hda.[ch]
|
||||
usr/src/cmd/bhyve/pci_hostbridge.c
|
||||
usr/src/cmd/bhyve/pci_irq.[ch]
|
||||
usr/src/cmd/bhyve/pci_lpc.[ch]
|
||||
usr/src/cmd/bhyve/pci_nvme.c
|
||||
usr/src/cmd/bhyve/pci_passthru.[ch]
|
||||
usr/src/cmd/bhyve/pci_uart.c
|
||||
usr/src/cmd/bhyve/pci_virtio_9p.c
|
||||
usr/src/cmd/bhyve/pci_virtio_block.c
|
||||
usr/src/cmd/bhyve/pci_virtio_console.c
|
||||
usr/src/cmd/bhyve/pci_virtio_input.c
|
||||
usr/src/cmd/bhyve/pci_virtio_net.c
|
||||
usr/src/cmd/bhyve/pci_virtio_rnd.c
|
||||
usr/src/cmd/bhyve/pci_virtio_scsi.c
|
||||
usr/src/cmd/bhyve/pci_xhci.[ch]
|
||||
usr/src/cmd/bhyve/pctestdev.c
|
||||
usr/src/cmd/bhyve/pm.c
|
||||
usr/src/cmd/bhyve/post.c
|
||||
usr/src/cmd/bhyve/ps2kbd.[ch]
|
||||
usr/src/cmd/bhyve/ps2mouse.[ch]
|
||||
usr/src/cmd/bhyve/qemu_fwcfg.[ch]
|
||||
usr/src/cmd/bhyve/qemu_loader.[ch]
|
||||
usr/src/cmd/bhyve/rtc.[ch]
|
||||
usr/src/cmd/bhyve/smbiostbl.[ch]
|
||||
usr/src/cmd/bhyve/sockstream.[ch]
|
||||
usr/src/cmd/bhyve/spinup_ap.[ch]
|
||||
usr/src/cmd/bhyve/task_switch.c
|
||||
usr/src/cmd/bhyve/tpm*
|
||||
usr/src/cmd/bhyve/uart_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_mouse.c
|
||||
usr/src/cmd/bhyve/vga.[ch]
|
||||
usr/src/cmd/bhyve/vmgenc.[ch]
|
||||
usr/src/cmd/bhyve/virtio.[ch]
|
||||
usr/src/cmd/bhyve/xmsr.[ch]
|
||||
usr/src/cmd/bhyve/amd64/atkbdc.[ch]
|
||||
usr/src/cmd/bhyve/amd64/bhyverun_machdep.c
|
||||
usr/src/cmd/bhyve/amd64/e820.[ch]
|
||||
usr/src/cmd/bhyve/amd64/fwctl.[ch]
|
||||
usr/src/cmd/bhyve/amd64/inout.[ch]
|
||||
usr/src/cmd/bhyve/amd64/mptbl.[ch]
|
||||
usr/src/cmd/bhyve/amd64/pci_lpc.c
|
||||
usr/src/cmd/bhyve/amd64/pm.c
|
||||
usr/src/cmd/bhyve/amd64/ps2kbd.c
|
||||
usr/src/cmd/bhyve/amd64/ps2mouse.c
|
||||
usr/src/cmd/bhyve/amd64/rtc.h
|
||||
usr/src/cmd/bhyve/amd64/spinup_ap.c
|
||||
usr/src/cmd/bhyve/amd64/task_switch.c
|
||||
usr/src/cmd/bhyve/amd64/vga.c
|
||||
usr/src/cmd/bhyve/amd64/vmexit.c
|
||||
usr/src/cmd/bhyve/amd64/xmsr.c
|
||||
usr/src/cmd/bhyve/common/acpi.[ch]
|
||||
usr/src/cmd/bhyve/common/acpi_device.[ch]
|
||||
usr/src/cmd/bhyve/common/audio.[ch]
|
||||
usr/src/cmd/bhyve/common/basl.[ch]
|
||||
usr/src/cmd/bhyve/common/bhyvegc.c
|
||||
usr/src/cmd/bhyve/common/bhyverun.c
|
||||
usr/src/cmd/bhyve/common/block_if.[ch]
|
||||
usr/src/cmd/bhyve/common/bootrom.c
|
||||
usr/src/cmd/bhyve/common/console.h
|
||||
usr/src/cmd/bhyve/common/crc16.h
|
||||
usr/src/cmd/bhyve/common/debug.h
|
||||
usr/src/cmd/bhyve/common/gdb.c
|
||||
usr/src/cmd/bhyve/common/hda_codec.c
|
||||
usr/src/cmd/bhyve/common/hda_reg.h
|
||||
usr/src/cmd/bhyve/common/hdac_reg.h
|
||||
usr/src/cmd/bhyve/common/iov.c
|
||||
usr/src/cmd/bhyve/common/mem.[ch]
|
||||
usr/src/cmd/bhyve/common/mevent.[ch]
|
||||
usr/src/cmd/bhyve/common/net_backend_dlpi.c
|
||||
usr/src/cmd/bhyve/common/net_backends.[ch]
|
||||
usr/src/cmd/bhyve/common/net_backends_priv.h
|
||||
usr/src/cmd/bhyve/common/net_utils.[ch]
|
||||
usr/src/cmd/bhyve/common/pci_ahci.c
|
||||
usr/src/cmd/bhyve/common/pci_e82545.c
|
||||
usr/src/cmd/bhyve/common/pci_emul.[ch]
|
||||
usr/src/cmd/bhyve/common/pci_fbuf.c
|
||||
usr/src/cmd/bhyve/common/pci_hda.[ch]
|
||||
usr/src/cmd/bhyve/common/pci_hostbridge.c
|
||||
usr/src/cmd/bhyve/common/pci_irq.c
|
||||
usr/src/cmd/bhyve/common/pci_nvme.c
|
||||
usr/src/cmd/bhyve/common/pci_passthru.[ch]
|
||||
usr/src/cmd/bhyve/common/pci_uart.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_9p.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_block.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_console.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_input.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_net.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_rnd.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_scsi.c
|
||||
usr/src/cmd/bhyve/common/pci_xhci.[ch]
|
||||
usr/src/cmd/bhyve/common/pctestdev.c
|
||||
usr/src/cmd/bhyve/common/privileges.c
|
||||
usr/src/cmd/bhyve/common/qemu_fwcfg.[ch]
|
||||
usr/src/cmd/bhyve/common/qemu_loader.[ch]
|
||||
usr/src/cmd/bhyve/common/smbiostbl.[ch]
|
||||
usr/src/cmd/bhyve/common/tpm_device.c
|
||||
usr/src/cmd/bhyve/common/tpm_emul.h
|
||||
usr/src/cmd/bhyve/common/tpm_emul_passthru.c
|
||||
usr/src/cmd/bhyve/common/tpm_intf.h
|
||||
usr/src/cmd/bhyve/common/tpm_intf_crb.c
|
||||
usr/src/cmd/bhyve/common/tpm_ppi.h
|
||||
usr/src/cmd/bhyve/common/tpm_ppi_qemu.c
|
||||
usr/src/cmd/bhyve/common/uart_backend.c
|
||||
usr/src/cmd/bhyve/common/uart_emul.c
|
||||
usr/src/cmd/bhyve/common/usb_emul.[ch]
|
||||
usr/src/cmd/bhyve/common/usb_mouse.c
|
||||
usr/src/cmd/bhyve/common/virtio.[ch]
|
||||
usr/src/cmd/bhyve/common/vmgenc.c
|
||||
usr/src/cmd/bhyve/test/tests/mevent/mevent_test.c
|
||||
usr/src/cmd/bhyvectl/bhyvectl.c
|
||||
usr/src/compat/bhyve/*
|
||||
usr/src/contrib/bhyve/*
|
||||
|
|
|
@ -384,44 +384,27 @@ usr/src/uts/intel/sys/acpi/platform/acwin64.h
|
|||
|
||||
# bhyve sources
|
||||
syntax: glob
|
||||
usr/src/cmd/bhyve/acpi.h
|
||||
usr/src/cmd/bhyve/acpi_device.h
|
||||
usr/src/cmd/bhyve/ahci.h
|
||||
usr/src/cmd/bhyve/atkbdc.h
|
||||
usr/src/cmd/bhyve/audio.h
|
||||
usr/src/cmd/bhyve/basl.h
|
||||
usr/src/cmd/bhyve/bhyvegc.h
|
||||
usr/src/cmd/bhyve/bhyverun.h
|
||||
usr/src/cmd/bhyve/block_if.h
|
||||
usr/src/cmd/bhyve/bootrom.h
|
||||
usr/src/cmd/bhyve/console.h
|
||||
usr/src/cmd/bhyve/crc16.h
|
||||
usr/src/cmd/bhyve/dbgport.h
|
||||
usr/src/cmd/bhyve/debug.h
|
||||
usr/src/cmd/bhyve/e820.h
|
||||
usr/src/cmd/bhyve/inout.h
|
||||
usr/src/cmd/bhyve/ioapic.h
|
||||
usr/src/cmd/bhyve/kernemu_dev.h
|
||||
usr/src/cmd/bhyve/mem.h
|
||||
usr/src/cmd/bhyve/mptbl.h
|
||||
usr/src/cmd/bhyve/pci_emul.h
|
||||
usr/src/cmd/bhyve/pci_hda.h
|
||||
usr/src/cmd/bhyve/pci_irq.h
|
||||
usr/src/cmd/bhyve/pci_lpc.h
|
||||
usr/src/cmd/bhyve/pctestdev.h
|
||||
usr/src/cmd/bhyve/ps2kbd.h
|
||||
usr/src/cmd/bhyve/ps2mouse.h
|
||||
usr/src/cmd/bhyve/qemu_loader.h
|
||||
usr/src/cmd/bhyve/rtc.h
|
||||
usr/src/cmd/bhyve/smbiostbl.h
|
||||
usr/src/cmd/bhyve/sockstream.h
|
||||
usr/src/cmd/bhyve/spinup_ap.h
|
||||
usr/src/cmd/bhyve/tpm_*.h
|
||||
usr/src/cmd/bhyve/uart_emul.h
|
||||
usr/src/cmd/bhyve/vga.h
|
||||
usr/src/cmd/bhyve/vmgenc.h
|
||||
usr/src/cmd/bhyve/virtio.h
|
||||
usr/src/cmd/bhyve/xmsr.h
|
||||
usr/src/cmd/bhyve/amd64/e820.h
|
||||
usr/src/cmd/bhyve/amd64/ioapic.h
|
||||
usr/src/cmd/bhyve/amd64/kernemu_dev.h
|
||||
usr/src/cmd/bhyve/amd64/spinup_ap.h
|
||||
usr/src/cmd/bhyve/amd64/xmsr.h
|
||||
usr/src/cmd/bhyve/common/acpi_device.h
|
||||
usr/src/cmd/bhyve/common/audio.h
|
||||
usr/src/cmd/bhyve/common/basl.h
|
||||
usr/src/cmd/bhyve/common/bhyverun.h
|
||||
usr/src/cmd/bhyve/common/bootrom.h
|
||||
usr/src/cmd/bhyve/common/crc16.h
|
||||
usr/src/cmd/bhyve/common/debug.h
|
||||
usr/src/cmd/bhyve/common/pci_irq.h
|
||||
usr/src/cmd/bhyve/common/pctestdev.h
|
||||
usr/src/cmd/bhyve/common/qemu_loader.h
|
||||
usr/src/cmd/bhyve/common/sockstream.h
|
||||
usr/src/cmd/bhyve/common/tpm_device.h
|
||||
usr/src/cmd/bhyve/common/tpm_emul.h
|
||||
usr/src/cmd/bhyve/common/tpm_intf.h
|
||||
usr/src/cmd/bhyve/common/tpm_ppi.h
|
||||
usr/src/cmd/bhyve/common/vmgenc.h
|
||||
usr/src/compat/bhyve/*
|
||||
usr/src/contrib/bhyve/*
|
||||
usr/src/lib/libvmmapi/common/vmmapi.h
|
||||
|
|
|
@ -42,72 +42,32 @@ usr/src/data/ucode/amd/*
|
|||
usr/src/data/ucode/intel/*
|
||||
|
||||
# bhyve sources
|
||||
usr/src/cmd/bhyve/acpi.[ch]
|
||||
usr/src/cmd/bhyve/acpi_device.[ch]
|
||||
usr/src/cmd/bhyve/ahci.h
|
||||
usr/src/cmd/bhyve/atkbdc.[ch]
|
||||
usr/src/cmd/bhyve/audio.[ch]
|
||||
usr/src/cmd/bhyve/basl.[ch]
|
||||
usr/src/cmd/bhyve/crc16.[ch]
|
||||
usr/src/cmd/bhyve/bhyvegc.[ch]
|
||||
usr/src/cmd/bhyve/bhyverun.[ch]
|
||||
usr/src/cmd/bhyve/block_if.[ch]
|
||||
usr/src/cmd/bhyve/bootrom.[ch]
|
||||
usr/src/cmd/bhyve/config.[ch]
|
||||
usr/src/cmd/bhyve/console.[ch]
|
||||
usr/src/cmd/bhyve/consport.c
|
||||
usr/src/cmd/bhyve/dbgport.[ch]
|
||||
usr/src/cmd/bhyve/e820.[ch]
|
||||
usr/src/cmd/bhyve/fwctl.[ch]
|
||||
usr/src/cmd/bhyve/gdb.[ch]
|
||||
usr/src/cmd/bhyve/hda_codec.c
|
||||
usr/src/cmd/bhyve/hda_reg.h
|
||||
usr/src/cmd/bhyve/hdac_reg.h
|
||||
usr/src/cmd/bhyve/inout.[ch]
|
||||
usr/src/cmd/bhyve/ioapic.[ch]
|
||||
usr/src/cmd/bhyve/mem.[ch]
|
||||
usr/src/cmd/bhyve/mevent.[ch]
|
||||
usr/src/cmd/bhyve/mevent_test.c
|
||||
usr/src/cmd/bhyve/mptbl.[ch]
|
||||
usr/src/cmd/bhyve/net_utils.[ch]
|
||||
usr/src/cmd/bhyve/net_backends.[ch]
|
||||
usr/src/cmd/bhyve/pci_ahci.c
|
||||
usr/src/cmd/bhyve/pci_e82545.c
|
||||
usr/src/cmd/bhyve/pci_emul.[ch]
|
||||
usr/src/cmd/bhyve/pci_fbuf.c
|
||||
usr/src/cmd/bhyve/pci_hda.[ch]
|
||||
usr/src/cmd/bhyve/pci_hostbridge.c
|
||||
usr/src/cmd/bhyve/pci_irq.[ch]
|
||||
usr/src/cmd/bhyve/pci_lpc.[ch]
|
||||
usr/src/cmd/bhyve/pci_nvme.c
|
||||
usr/src/cmd/bhyve/pci_passthru.[ch]
|
||||
usr/src/cmd/bhyve/pci_uart.c
|
||||
usr/src/cmd/bhyve/pci_virtio_9p.c
|
||||
usr/src/cmd/bhyve/pci_virtio_block.c
|
||||
usr/src/cmd/bhyve/pci_virtio_console.c
|
||||
usr/src/cmd/bhyve/pci_virtio_input.c
|
||||
usr/src/cmd/bhyve/pci_virtio_net.c
|
||||
usr/src/cmd/bhyve/pci_virtio_rnd.c
|
||||
usr/src/cmd/bhyve/pci_virtio_scsi.c
|
||||
usr/src/cmd/bhyve/pci_xhci.[ch]
|
||||
usr/src/cmd/bhyve/pm.c
|
||||
usr/src/cmd/bhyve/pmtmr.c
|
||||
usr/src/cmd/bhyve/post.c
|
||||
usr/src/cmd/bhyve/ps2kbd.[ch]
|
||||
usr/src/cmd/bhyve/ps2mouse.[ch]
|
||||
usr/src/cmd/bhyve/qemu_fwcfg.c
|
||||
usr/src/cmd/bhyve/rtc.[ch]
|
||||
usr/src/cmd/bhyve/smbiostbl.[ch]
|
||||
usr/src/cmd/bhyve/sockstream.[ch]
|
||||
usr/src/cmd/bhyve/spinup_ap.[ch]
|
||||
usr/src/cmd/bhyve/task_switch.c
|
||||
usr/src/cmd/bhyve/tpm_emul_passthru.c
|
||||
usr/src/cmd/bhyve/uart_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_emul.[ch]
|
||||
usr/src/cmd/bhyve/usb_mouse.c
|
||||
usr/src/cmd/bhyve/vga.[ch]
|
||||
usr/src/cmd/bhyve/virtio.[ch]
|
||||
usr/src/cmd/bhyve/xmsr.[ch]
|
||||
usr/src/cmd/bhyve/amd64/e820.c
|
||||
usr/src/cmd/bhyve/amd64/fwctl.c
|
||||
usr/src/cmd/bhyve/amd64/mptbl.c
|
||||
usr/src/cmd/bhyve/amd64/pci_lpc.c
|
||||
usr/src/cmd/bhyve/amd64/ps2kbd.c
|
||||
usr/src/cmd/bhyve/common/acpi.[ch]
|
||||
usr/src/cmd/bhyve/common/basl.c
|
||||
usr/src/cmd/bhyve/common/block_if.h
|
||||
usr/src/cmd/bhyve/common/config.h
|
||||
usr/src/cmd/bhyve/common/hda_codec.c
|
||||
usr/src/cmd/bhyve/common/mem.h
|
||||
usr/src/cmd/bhyve/common/net_backends.c
|
||||
usr/src/cmd/bhyve/common/pci_e82545.c
|
||||
usr/src/cmd/bhyve/common/pci_emul.h
|
||||
usr/src/cmd/bhyve/common/pci_nvme.c
|
||||
usr/src/cmd/bhyve/common/pci_passthru.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_console.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_net.c
|
||||
usr/src/cmd/bhyve/common/pci_virtio_scsi.c
|
||||
usr/src/cmd/bhyve/common/pci_xhci.h
|
||||
usr/src/cmd/bhyve/common/qemu_fwcfg.c
|
||||
usr/src/cmd/bhyve/common/smbiostbl.c
|
||||
usr/src/cmd/bhyve/common/tpm_emul_passthru.c
|
||||
usr/src/cmd/bhyve/common/uart_emul.c
|
||||
usr/src/cmd/bhyve/common/usb_emul.h
|
||||
usr/src/cmd/bhyve/common/usb_mouse.c
|
||||
usr/src/cmd/bhyvectl/bhyvectl.c
|
||||
usr/src/contrib/bhyve/*
|
||||
usr/src/data/bhyve/kbdlayout/default
|
||||
|
|
|
@ -10,177 +10,21 @@
|
|||
#
|
||||
|
||||
#
|
||||
# Copyright 2014 Pluribus Networks Inc.
|
||||
# Copyright 2020 Joyent, Inc.
|
||||
# Copyright 2020 Oxide Computer Company
|
||||
# Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
|
||||
# Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
|
||||
#
|
||||
|
||||
PROG = bhyve
|
||||
include $(SRC)/cmd/Makefile.cmd
|
||||
|
||||
include ../Makefile.cmd
|
||||
include ../Makefile.cmd.64
|
||||
include ../Makefile.ctf
|
||||
SUBDIRS = $(MACH64) test
|
||||
|
||||
SUBDIRS = test
|
||||
|
||||
all := TARGET = all
|
||||
install := TARGET = install
|
||||
clean := TARGET = clean
|
||||
clobber := TARGET = clobber
|
||||
|
||||
SRCS = acpi.c \
|
||||
acpi_device.c \
|
||||
atkbdc.c \
|
||||
basl.c \
|
||||
bhyvegc.c \
|
||||
bhyverun.c \
|
||||
block_if.c \
|
||||
bootrom.c \
|
||||
config.c \
|
||||
console.c \
|
||||
crc16.c \
|
||||
e820.c \
|
||||
fwctl.c \
|
||||
gdb.c \
|
||||
hexdump.c \
|
||||
inout.c \
|
||||
ioapic.c \
|
||||
iov.c \
|
||||
mem.c \
|
||||
mevent.c \
|
||||
mptbl.c \
|
||||
net_backends.c \
|
||||
net_utils.c \
|
||||
pci_ahci.c \
|
||||
pci_e82545.c \
|
||||
pci_emul.c \
|
||||
pci_fbuf.c \
|
||||
pci_hostbridge.c \
|
||||
pci_irq.c \
|
||||
pci_lpc.c \
|
||||
pci_nvme.c \
|
||||
pci_passthru.c \
|
||||
pci_uart.c \
|
||||
pci_virtio_9p.c \
|
||||
pci_virtio_block.c \
|
||||
pci_virtio_console.c \
|
||||
pci_virtio_net.c \
|
||||
pci_virtio_rnd.c \
|
||||
pci_virtio_viona.c \
|
||||
pci_xhci.c \
|
||||
pctestdev.c \
|
||||
pm.c \
|
||||
post.c \
|
||||
privileges.c \
|
||||
ps2kbd.c \
|
||||
ps2mouse.c \
|
||||
qemu_fwcfg.c \
|
||||
qemu_loader.c \
|
||||
rfb.c \
|
||||
rtc.c \
|
||||
smbiostbl.c \
|
||||
sockstream.c \
|
||||
spinup_ap.c \
|
||||
task_switch.c \
|
||||
tpm_device.c \
|
||||
tpm_emul_passthru.c \
|
||||
tpm_intf_crb.c \
|
||||
tpm_ppi_qemu.c \
|
||||
uart_emul.c \
|
||||
usb_emul.c \
|
||||
usb_mouse.c \
|
||||
vga.c \
|
||||
virtio.c \
|
||||
vmgenc.c \
|
||||
xmsr.c \
|
||||
bhyve_sol_glue.c
|
||||
|
||||
# We are not yet performing instruction emulation in userspace, so going to the
|
||||
# trouble of fixing the header tangle for this is not worth the complexity.
|
||||
#kernemu_dev.c \
|
||||
|
||||
# The virtio-scsi driver appears to include a slew of materials from FreeBSD's
|
||||
# native SCSI implementation. We will omit that complexity for now.
|
||||
#ctl_util.c \
|
||||
#ctl_scsi_all.c \
|
||||
#pci_virtio_scsi.c \
|
||||
|
||||
# The audio backend in FreeBSD is different than the one found in audio_oss.h
|
||||
#audio.c \
|
||||
#hda_codec.c \
|
||||
#pci_hda.c \
|
||||
|
||||
# The virtio input device expects to link to a FreeBSD /dev/input/eventX device
|
||||
#pci_virtio_input.c \
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
MEVENT_TEST_PROG = mevent_test
|
||||
MEVENT_TEST_SRCS = mevent.c mevent_test.c
|
||||
MEVENT_TEST_OBJS = $(MEVENT_TEST_SRCS:.c=.o)
|
||||
|
||||
CLEANFILES = $(OBJS) $(MEVENT_TEST_OBJS)
|
||||
CLOBBERFILES = $(PROG) $(MEVENT_TEST_PROG)
|
||||
|
||||
CFLAGS += $(CCVERBOSE)
|
||||
CFLAGS += -_gcc=-Wimplicit-function-declaration
|
||||
CPPFLAGS = -I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \
|
||||
-I$(COMPAT)/bhyve/amd64 -I$(CONTRIB)/bhyve/amd64 \
|
||||
-I$(CONTRIB)/bhyve/dev/usb/controller \
|
||||
-I$(CONTRIB)/bhyve/dev/mii \
|
||||
-I$(SRC)/lib/lib9p/common \
|
||||
-I$(SRC)/uts/common/io/e1000api \
|
||||
$(CPPFLAGS.master) \
|
||||
-I$(SRC)/uts/intel/io/vmm \
|
||||
-I$(SRC)/uts/common \
|
||||
-I$(SRC)/uts/intel \
|
||||
-DWITHOUT_CAPSICUM \
|
||||
-DOPENSSL_API_COMPAT=0x10100000L
|
||||
|
||||
SMOFF += all_func_returns
|
||||
rfb.o := SMOFF=
|
||||
|
||||
# Force c99 for everything
|
||||
CSTD= $(CSTD_GNU99)
|
||||
|
||||
$(PROG) := LDLIBS += \
|
||||
-l9p \
|
||||
-lcmdutils \
|
||||
-lcrypto \
|
||||
-ldladm \
|
||||
-ldlpi \
|
||||
-lidspace \
|
||||
-lmd \
|
||||
-lnsl \
|
||||
-lnvpair \
|
||||
-lsocket \
|
||||
-lumem \
|
||||
-luuid \
|
||||
-lvmmapi \
|
||||
-lz
|
||||
NATIVE_LIBS += libz.so libcrypto.so
|
||||
$(MEVENT_TEST_PROG) := LDLIBS += -lsocket
|
||||
$(PROG) := LDFLAGS += $(ZASLR)
|
||||
all := TARGET = all
|
||||
clean := TARGET = clean
|
||||
clobber := TARGET = clobber
|
||||
install := TARGET = install
|
||||
|
||||
.KEEP_STATE:
|
||||
|
||||
all: $(PROG) $(MEVENT_TEST_PROG) $(SUBDIRS)
|
||||
|
||||
$(PROG): $(OBJS)
|
||||
$(LINK.c) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
|
||||
$(POST_PROCESS)
|
||||
|
||||
$(MEVENT_TEST_PROG): $(MEVENT_TEST_OBJS)
|
||||
$(LINK.c) -o $@ $(MEVENT_TEST_OBJS) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
install: all $(ROOTUSRSBINPROG) $(SUBDIRS)
|
||||
|
||||
clean: $(SUBDIRS)
|
||||
$(RM) $(CLEANFILES)
|
||||
|
||||
clobber: clean $(SUBDIRS)
|
||||
$(RM) $(CLOBBERFILES)
|
||||
all clean clobber install: $(SUBDIRS)
|
||||
|
||||
$(SUBDIRS): FRC
|
||||
@cd $@; pwd; $(MAKE) $(TARGET)
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2014 Pluribus Networks Inc.
|
||||
# Copyright 2020 Joyent, Inc.
|
||||
# Copyright 2020 Oxide Computer Company
|
||||
# Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
|
||||
#
|
||||
|
||||
PROG = bhyve
|
||||
|
||||
include $(SRC)/cmd/Makefile.cmd
|
||||
include $(SRC)/cmd//Makefile.cmd.64
|
||||
include $(SRC)/cmd/Makefile.ctf
|
||||
|
||||
COMMON_OBJS = \
|
||||
acpi.o \
|
||||
acpi_device.o \
|
||||
basl.o \
|
||||
bhyvegc.o \
|
||||
bhyverun.o \
|
||||
block_if.o \
|
||||
bootrom.o \
|
||||
config.o \
|
||||
console.o \
|
||||
crc16.o \
|
||||
gdb.o \
|
||||
hexdump.o \
|
||||
iov.o \
|
||||
mem.o \
|
||||
mevent.o \
|
||||
net_backend_dlpi.o \
|
||||
net_backends.o \
|
||||
net_utils.o \
|
||||
pci_ahci.o \
|
||||
pci_e82545.o \
|
||||
pci_emul.o \
|
||||
pci_hostbridge.o \
|
||||
pci_irq.o \
|
||||
pci_nvme.o \
|
||||
pci_uart.o \
|
||||
pci_virtio_9p.o \
|
||||
pci_virtio_block.o \
|
||||
pci_virtio_console.o \
|
||||
pci_virtio_net.o \
|
||||
pci_virtio_rnd.o \
|
||||
pci_virtio_viona.o \
|
||||
pci_xhci.o \
|
||||
privileges.o \
|
||||
qemu_fwcfg.o \
|
||||
qemu_loader.o \
|
||||
smbiostbl.o \
|
||||
sockstream.o \
|
||||
tpm_device.o \
|
||||
tpm_emul_passthru.o \
|
||||
tpm_intf_crb.o \
|
||||
tpm_ppi_qemu.o \
|
||||
uart_backend.o \
|
||||
uart_emul.o \
|
||||
usb_emul.o \
|
||||
usb_mouse.o \
|
||||
virtio.o \
|
||||
vmgenc.o \
|
||||
bhyve_sol_glue.o
|
||||
|
||||
CFLAGS += $(CCVERBOSE)
|
||||
CFLAGS += -_gcc=-Wimplicit-function-declaration
|
||||
CPPFLAGS = -I../common \
|
||||
-I$(COMPAT)/bhyve -I$(CONTRIB)/bhyve \
|
||||
-I$(COMPAT)/bhyve/amd64 -I$(CONTRIB)/bhyve/amd64 \
|
||||
-I$(CONTRIB)/bhyve/dev/usb/controller \
|
||||
-I$(CONTRIB)/bhyve/dev/mii \
|
||||
-I$(SRC)/lib/lib9p/common \
|
||||
-I$(SRC)/uts/common/io/e1000api \
|
||||
$(CPPFLAGS.master) \
|
||||
-I$(SRC)/uts/intel/io/vmm \
|
||||
-I$(SRC)/uts/common \
|
||||
-I$(SRC)/uts/intel \
|
||||
-DWITHOUT_CAPSICUM \
|
||||
-DOPENSSL_API_COMPAT=0x10100000L
|
||||
|
||||
SMOFF += all_func_returns
|
||||
rfb.o := SMOFF=
|
||||
|
||||
CSTD= $(CSTD_GNU99)
|
||||
|
||||
$(PROG) := LDLIBS += \
|
||||
-l9p \
|
||||
-lcmdutils \
|
||||
-lcrypto \
|
||||
-ldladm \
|
||||
-ldlpi \
|
||||
-lidspace \
|
||||
-lmd \
|
||||
-lnsl \
|
||||
-lnvpair \
|
||||
-lsocket \
|
||||
-lumem \
|
||||
-luuid \
|
||||
-lvmmapi \
|
||||
-lz
|
||||
NATIVE_LIBS += libz.so libcrypto.so
|
||||
$(PROG) := LDFLAGS += $(ZASLR)
|
||||
|
||||
OBJS = $(BHYVE_OBJS:%=pics/%)
|
||||
|
||||
CLEANFILES = $(OBJS)
|
||||
CLOBBERFILES = $(PROG)
|
||||
|
||||
all: pics $(PROG)
|
||||
|
||||
clean:
|
||||
$(RM) $(CLEANFILES)
|
||||
|
||||
clobber: clean
|
||||
$(RM) $(CLOBBERFILES)
|
||||
|
||||
pics: FRC
|
||||
$(MKDIR) -p $@
|
||||
|
||||
pics/%.o: ../common/%.c
|
||||
$(COMPILE.c) -c -o $@ $<
|
||||
$(POST_PROCESS_O)
|
||||
|
||||
pics/%.o: %.c
|
||||
$(COMPILE.c) -c -o $@ $<
|
||||
$(POST_PROCESS_O)
|
||||
|
||||
$(PROG): pics $(OBJS)
|
||||
$(LINK.c) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS)
|
||||
$(POST_PROCESS)
|
||||
|
||||
FRC:
|
|
@ -5,11 +5,11 @@ The bhyve userland code in this directory, and its associated libraries and
|
|||
parts of the kernel module have been updated to the latest upstream FreeBSD
|
||||
sources as of:
|
||||
|
||||
commit 6f7e9779fcb196e2d66720e1b97de89b69677208
|
||||
Author: Corvin Köhne <corvink@FreeBSD.org>
|
||||
Date: Wed Jul 27 14:47:54 2022 +0200
|
||||
commit a305f44d1404fbf386bb2b50ab7233ce9eabe0bb
|
||||
Author: Ed Maste <emaste@FreeBSD.org>
|
||||
Date: Thu Sep 19 14:57:42 2024 -0400
|
||||
|
||||
bhyve: add config option to load ACPI tables into memory
|
||||
bhyve: validate corb->wp to avoid infinite loop
|
||||
|
||||
Divergence Notes:
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
|
||||
#
|
||||
# Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
|
||||
#
|
||||
|
||||
BHYVE_OBJS = $(COMMON_OBJS) \
|
||||
atkbdc.o \
|
||||
bhyverun_machdep.o \
|
||||
e820.o \
|
||||
inout.o \
|
||||
ioapic.o \
|
||||
fwctl.o \
|
||||
mptbl.o \
|
||||
pci_fbuf.o \
|
||||
pci_lpc.o \
|
||||
pci_passthru.o \
|
||||
pctestdev.o \
|
||||
post.o \
|
||||
pm.o \
|
||||
ps2kbd.o \
|
||||
ps2mouse.o \
|
||||
rfb.o \
|
||||
rtc.o \
|
||||
spinup_ap.o \
|
||||
task_switch.o \
|
||||
vga.o \
|
||||
vmexit.o \
|
||||
xmsr.o
|
||||
|
||||
include ../Makefile.com
|
||||
|
||||
CPPFLAGS += -I.
|
||||
|
||||
install: all $(ROOTUSRSBINPROG)
|
|
@ -27,7 +27,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -0,0 +1,458 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2011 NetApp, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*
|
||||
* Copyright 2015 Pluribus Networks Inc.
|
||||
* Copyright 2018 Joyent, Inc.
|
||||
* Copyright 2022 Oxide Computer Company
|
||||
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/vmm.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vmm.h>
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "bhyverun.h"
|
||||
#include "bootrom.h"
|
||||
#include "acpi.h"
|
||||
#include "atkbdc.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "e820.h"
|
||||
#include "fwctl.h"
|
||||
#include "ioapic.h"
|
||||
#include "inout.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "kernemu_dev.h"
|
||||
#endif
|
||||
#include "mptbl.h"
|
||||
#include "pci_emul.h"
|
||||
#include "pci_irq.h"
|
||||
#include "spinup_ap.h"
|
||||
#include "pci_lpc.h"
|
||||
#include "rtc.h"
|
||||
#include "smbiostbl.h"
|
||||
#include "xmsr.h"
|
||||
|
||||
void
|
||||
bhyve_usage(int code)
|
||||
{
|
||||
const char *progname = getprogname();
|
||||
|
||||
fprintf(stderr,
|
||||
#ifdef __FreeBSD__
|
||||
"Usage: %s [-AaCDeHhPSuWwxY]\n"
|
||||
#else
|
||||
"Usage: %s [-aCDdeHhPSuWwxY]\n"
|
||||
#endif
|
||||
" %2$.*3$s [-c [[cpus=]numcpus][,sockets=n][,cores=n][,threads=n]]\n"
|
||||
#ifdef __FreeBSD__
|
||||
" %2$.*3$s [-G port] [-k config_file] [-l lpc] [-m mem] [-o var=value]\n"
|
||||
" %2$.*3$s [-p vcpu:hostcpu] [-r file] [-s pci] [-U uuid] vmname\n"
|
||||
|
||||
" -A: create ACPI tables\n"
|
||||
#else
|
||||
" %2$.*3$s [-k <config_file>] [-l <lpc>] [-m mem] [-o <var>=<value>]\n"
|
||||
" %2$.*3$s [-s <pci>] [-U uuid] vmname\n"
|
||||
#endif
|
||||
" -a: local apic is in xAPIC mode (deprecated)\n"
|
||||
#ifndef __FreeBSD__
|
||||
" -B type,key=value,...: set SMBIOS information\n"
|
||||
#endif
|
||||
" -C: include guest memory in core file\n"
|
||||
" -c: number of CPUs and/or topology specification\n"
|
||||
" -D: destroy on power-off\n"
|
||||
#ifndef __FreeBSD__
|
||||
" -d: suspend cpu at boot\n"
|
||||
#endif
|
||||
" -e: exit on unhandled I/O access\n"
|
||||
#ifdef __FreeBSD__
|
||||
" -G: start a debug server\n"
|
||||
#endif
|
||||
" -H: vmexit from the guest on HLT\n"
|
||||
" -h: help\n"
|
||||
" -k: key=value flat config file\n"
|
||||
" -K: PS2 keyboard layout\n"
|
||||
" -l: LPC device configuration\n"
|
||||
" -m: memory size\n"
|
||||
" -o: set config 'var' to 'value'\n"
|
||||
" -P: vmexit from the guest on pause\n"
|
||||
#ifdef __FreeBSD__
|
||||
" -p: pin 'vcpu' to 'hostcpu'\n"
|
||||
#endif
|
||||
" -S: guest memory cannot be swapped\n"
|
||||
" -s: <slot,driver,configinfo> PCI slot config\n"
|
||||
" -U: UUID\n"
|
||||
" -u: RTC keeps UTC time\n"
|
||||
" -W: force virtio to use single-vector MSI\n"
|
||||
" -w: ignore unimplemented MSRs\n"
|
||||
" -x: local APIC is in x2APIC mode\n"
|
||||
" -Y: disable MPtable generation\n",
|
||||
progname, "", (int)strlen(progname));
|
||||
|
||||
exit(code);
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_optparse(int argc, char **argv)
|
||||
{
|
||||
const char *optstr;
|
||||
int c;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
|
||||
#else
|
||||
/* +d, +B, -p */
|
||||
optstr = "adehuwxACDHIPSWYk:f:o:G:c:s:m:l:B:K:U:";
|
||||
#endif
|
||||
while ((c = getopt(argc, argv, optstr)) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
set_config_bool("x86.x2apic", false);
|
||||
break;
|
||||
case 'A':
|
||||
set_config_bool("acpi_tables", true);
|
||||
break;
|
||||
case 'D':
|
||||
set_config_bool("destroy_on_poweroff", true);
|
||||
break;
|
||||
#ifndef __FreeBSD__
|
||||
case 'B':
|
||||
if (smbios_parse(optarg) != 0) {
|
||||
errx(EX_USAGE, "invalid SMBIOS "
|
||||
"configuration '%s'", optarg);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
set_config_bool("suspend_at_boot", true);
|
||||
break;
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
case 'p':
|
||||
if (pincpu_parse(optarg) != 0) {
|
||||
errx(EX_USAGE, "invalid vcpu pinning "
|
||||
"configuration '%s'", optarg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 'c':
|
||||
if (bhyve_topology_parse(optarg) != 0) {
|
||||
errx(EX_USAGE, "invalid cpu topology "
|
||||
"'%s'", optarg);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
set_config_bool("memory.guest_in_core", true);
|
||||
break;
|
||||
case 'f':
|
||||
if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) {
|
||||
errx(EX_USAGE, "invalid fwcfg item '%s'", optarg);
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
bhyve_parse_gdb_options(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
bhyve_parse_simple_config_file(optarg);
|
||||
break;
|
||||
case 'K':
|
||||
set_config_value("keyboard.layout", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
if (strncmp(optarg, "help", strlen(optarg)) == 0) {
|
||||
lpc_print_supported_devices();
|
||||
exit(0);
|
||||
} else if (lpc_device_parse(optarg) != 0) {
|
||||
errx(EX_USAGE, "invalid lpc device "
|
||||
"configuration '%s'", optarg);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (strncmp(optarg, "help", strlen(optarg)) == 0) {
|
||||
pci_print_supported_devices();
|
||||
exit(0);
|
||||
} else if (pci_parse_slot(optarg) != 0)
|
||||
exit(4);
|
||||
else
|
||||
break;
|
||||
case 'S':
|
||||
set_config_bool("memory.wired", true);
|
||||
break;
|
||||
case 'm':
|
||||
set_config_value("memory.size", optarg);
|
||||
break;
|
||||
case 'o':
|
||||
if (!bhyve_parse_config_option(optarg))
|
||||
errx(EX_USAGE, "invalid configuration option '%s'", optarg);
|
||||
break;
|
||||
case 'H':
|
||||
set_config_bool("x86.vmexit_on_hlt", true);
|
||||
break;
|
||||
case 'I':
|
||||
/*
|
||||
* The "-I" option was used to add an ioapic to the
|
||||
* virtual machine.
|
||||
*
|
||||
* An ioapic is now provided unconditionally for each
|
||||
* virtual machine and this option is now deprecated.
|
||||
*/
|
||||
break;
|
||||
case 'P':
|
||||
set_config_bool("x86.vmexit_on_pause", true);
|
||||
break;
|
||||
case 'e':
|
||||
set_config_bool("x86.strictio", true);
|
||||
break;
|
||||
case 'u':
|
||||
set_config_bool("rtc.use_localtime", false);
|
||||
break;
|
||||
case 'U':
|
||||
set_config_value("uuid", optarg);
|
||||
break;
|
||||
case 'w':
|
||||
set_config_bool("x86.strictmsr", false);
|
||||
break;
|
||||
case 'W':
|
||||
set_config_bool("virtio_msix", false);
|
||||
break;
|
||||
case 'x':
|
||||
set_config_bool("x86.x2apic", true);
|
||||
break;
|
||||
case 'Y':
|
||||
set_config_bool("x86.mptable", false);
|
||||
break;
|
||||
case 'h':
|
||||
bhyve_usage(0);
|
||||
default:
|
||||
bhyve_usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle backwards compatibility aliases in config options. */
|
||||
if (get_config_value("lpc.bootrom") != NULL &&
|
||||
get_config_value("bootrom") == NULL) {
|
||||
warnx("lpc.bootrom is deprecated, use '-o bootrom' instead");
|
||||
set_config_value("bootrom", get_config_value("lpc.bootrom"));
|
||||
}
|
||||
if (get_config_value("lpc.bootvars") != NULL &&
|
||||
get_config_value("bootvars") == NULL) {
|
||||
warnx("lpc.bootvars is deprecated, use '-o bootvars' instead");
|
||||
set_config_value("bootvars", get_config_value("lpc.bootvars"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_init_config(void)
|
||||
{
|
||||
init_config();
|
||||
|
||||
/* Set default values prior to option parsing. */
|
||||
set_config_bool("acpi_tables", false);
|
||||
set_config_bool("acpi_tables_in_memory", true);
|
||||
set_config_value("memory.size", "256M");
|
||||
set_config_bool("x86.strictmsr", true);
|
||||
set_config_value("lpc.fwcfg", "bhyve");
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_init_vcpu(struct vcpu *vcpu)
|
||||
{
|
||||
int err, tmp;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (get_config_bool_default("x86.vmexit_on_hlt", false)) {
|
||||
err = vm_get_capability(vcpu, VM_CAP_HALT_EXIT, &tmp);
|
||||
if (err < 0) {
|
||||
EPRINTLN("VM exit on HLT not supported");
|
||||
exit(4);
|
||||
}
|
||||
vm_set_capability(vcpu, VM_CAP_HALT_EXIT, 1);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* We insist that vmexit-on-hlt is available on the host CPU, and enable
|
||||
* it by default. Configuration of that feature is done with both of
|
||||
* those facts in mind.
|
||||
*/
|
||||
tmp = (int)get_config_bool_default("x86.vmexit_on_hlt", true);
|
||||
err = vm_set_capability(vcpu, VM_CAP_HALT_EXIT, tmp);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "VM exit on HLT not supported\n");
|
||||
exit(4);
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
if (get_config_bool_default("x86.vmexit_on_pause", false)) {
|
||||
/*
|
||||
* pause exit support required for this mode
|
||||
*/
|
||||
err = vm_get_capability(vcpu, VM_CAP_PAUSE_EXIT, &tmp);
|
||||
if (err < 0) {
|
||||
EPRINTLN("SMP mux requested, no pause support");
|
||||
exit(4);
|
||||
}
|
||||
vm_set_capability(vcpu, VM_CAP_PAUSE_EXIT, 1);
|
||||
}
|
||||
|
||||
if (get_config_bool_default("x86.x2apic", false))
|
||||
err = vm_set_x2apic_state(vcpu, X2APIC_ENABLED);
|
||||
else
|
||||
err = vm_set_x2apic_state(vcpu, X2APIC_DISABLED);
|
||||
|
||||
if (err) {
|
||||
EPRINTLN("Unable to set x2apic state (%d)", err);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
vm_set_capability(vcpu, VM_CAP_ENABLE_INVPCID, 1);
|
||||
|
||||
err = vm_set_capability(vcpu, VM_CAP_IPI_EXIT, 1);
|
||||
assert(err == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_start_vcpu(struct vcpu *vcpu, bool bsp, bool suspend)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!bsp) {
|
||||
#ifndef __FreeBSD__
|
||||
/*
|
||||
* On illumos, all APs are spun up halted and run-state
|
||||
* transitions (INIT, SIPI, etc) are handled in-kernel.
|
||||
*/
|
||||
spinup_ap(vcpu, 0);
|
||||
#endif
|
||||
|
||||
bhyve_init_vcpu(vcpu);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* Enable the 'unrestricted guest' mode for APs.
|
||||
*
|
||||
* APs startup in power-on 16-bit mode.
|
||||
*/
|
||||
error = vm_set_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
|
||||
assert(error == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
/*
|
||||
* The value of 'suspend' for the BSP depends on whether the -d
|
||||
* (suspend_at_boot) flag was given to bhyve. Regardless of that
|
||||
* value we always want to set the BSP to VRS_RUN and all others to
|
||||
* VRS_HALT.
|
||||
*/
|
||||
error = vm_set_run_state(vcpu, bsp ? VRS_RUN : VRS_HALT, 0);
|
||||
assert(error == 0);
|
||||
#endif
|
||||
|
||||
fbsdrun_addcpu(vcpu_id(vcpu), suspend);
|
||||
}
|
||||
|
||||
int
|
||||
bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp __unused)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = init_msr();
|
||||
if (error != 0)
|
||||
return (error);
|
||||
init_inout();
|
||||
#ifdef __FreeBSD__
|
||||
kernemu_dev_init();
|
||||
#endif
|
||||
atkbdc_init(ctx);
|
||||
pci_irq_init(ctx);
|
||||
ioapic_init(ctx);
|
||||
rtc_init(ctx);
|
||||
sci_init(ctx);
|
||||
#ifndef __FreeBSD__
|
||||
pmtmr_init(ctx);
|
||||
#endif
|
||||
error = e820_init(ctx);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
error = bootrom_loadrom(ctx);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
if (get_config_bool_default("e820.debug", false))
|
||||
e820_dump_table();
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp __unused)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (get_config_bool_default("x86.mptable", true)) {
|
||||
error = mptable_build(ctx, guest_ncpus);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
error = smbios_build(ctx);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
error = e820_finalize();
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
if (bootrom_boot() && strcmp(lpc_fwcfg(), "bhyve") == 0)
|
||||
fwctl_init();
|
||||
|
||||
if (get_config_bool("acpi_tables")) {
|
||||
error = acpi_build(ctx, guest_ncpus);
|
||||
assert(error == 0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "e820.h"
|
||||
#include "qemu_fwcfg.h"
|
||||
|
||||
|
@ -93,11 +94,11 @@ e820_dump_table(void)
|
|||
struct e820_element *element;
|
||||
uint64_t i;
|
||||
|
||||
fprintf(stderr, "E820 map:\n");
|
||||
EPRINTLN("E820 map:");
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(element, &e820_table, chain) {
|
||||
fprintf(stderr, " (%4lu) [%16lx, %16lx] %s\n", i,
|
||||
EPRINTLN(" (%4lu) [%16lx, %16lx] %s", i,
|
||||
element->base, element->end,
|
||||
e820_get_type_name(element->type));
|
||||
|
||||
|
@ -105,7 +106,7 @@ e820_dump_table(void)
|
|||
}
|
||||
}
|
||||
|
||||
struct qemu_fwcfg_item *
|
||||
static struct qemu_fwcfg_item *
|
||||
e820_get_fwcfg_item(void)
|
||||
{
|
||||
struct qemu_fwcfg_item *fwcfg_item;
|
||||
|
@ -202,8 +203,19 @@ e820_add_entry(const uint64_t base, const uint64_t end,
|
|||
assert(element->type == E820_TYPE_MEMORY);
|
||||
/* New element should fit into existing system memory element. */
|
||||
assert(base >= element->base && end <= element->end);
|
||||
|
||||
if (base == element->base) {
|
||||
if (base == element->base && end == element->end) {
|
||||
/*
|
||||
* The new entry replaces an existing one.
|
||||
*
|
||||
* Old table:
|
||||
* [ 0x1000, 0x4000] RAM <-- element
|
||||
* New table:
|
||||
* [ 0x1000, 0x4000] Reserved
|
||||
*/
|
||||
TAILQ_INSERT_BEFORE(element, new_element, chain);
|
||||
TAILQ_REMOVE(&e820_table, element, chain);
|
||||
free(element);
|
||||
} else if (base == element->base) {
|
||||
/*
|
||||
* New element at system memory base boundary. Add new
|
||||
* element before current and adjust the base of the old
|
||||
|
@ -460,3 +472,27 @@ e820_init(struct vmctx *const ctx)
|
|||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
e820_finalize(void)
|
||||
{
|
||||
struct qemu_fwcfg_item *e820_fwcfg_item;
|
||||
int error;
|
||||
|
||||
e820_fwcfg_item = e820_get_fwcfg_item();
|
||||
if (e820_fwcfg_item == NULL) {
|
||||
warnx("invalid e820 table");
|
||||
return (ENOMEM);
|
||||
}
|
||||
error = qemu_fwcfg_add_file("etc/e820",
|
||||
e820_fwcfg_item->size, e820_fwcfg_item->data);
|
||||
if (error != 0) {
|
||||
warnx("could not add qemu fwcfg etc/e820");
|
||||
free(e820_fwcfg_item->data);
|
||||
free(e820_fwcfg_item);
|
||||
return (error);
|
||||
}
|
||||
free(e820_fwcfg_item);
|
||||
|
||||
return (0);
|
||||
}
|
|
@ -41,5 +41,5 @@ uint64_t e820_alloc(const uint64_t address, const uint64_t length,
|
|||
const uint64_t alignment, const enum e820_memory_type type,
|
||||
const enum e820_allocation_strategy strategy);
|
||||
void e820_dump_table(void);
|
||||
struct qemu_fwcfg_item *e820_get_fwcfg_item(void);
|
||||
int e820_init(struct vmctx *const ctx);
|
||||
int e820_finalize(void);
|
|
@ -30,7 +30,6 @@
|
|||
* Guest firmware interface. Uses i/o ports x510/x511 as Qemu does,
|
||||
* but with a request/response messaging protocol.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -64,8 +63,7 @@
|
|||
* Back-end state-machine
|
||||
*/
|
||||
static enum state {
|
||||
IDENT_WAIT,
|
||||
IDENT_SEND,
|
||||
IDENT,
|
||||
REQ,
|
||||
RESP
|
||||
} be_state;
|
||||
|
@ -76,7 +74,7 @@ static u_int ident_idx;
|
|||
struct op_info {
|
||||
int op;
|
||||
int (*op_start)(uint32_t len);
|
||||
void (*op_data)(uint32_t data, uint32_t len);
|
||||
void (*op_data)(uint32_t data);
|
||||
int (*op_result)(struct iovec **data);
|
||||
void (*op_done)(struct iovec *data);
|
||||
};
|
||||
|
@ -121,7 +119,7 @@ errop_start(uint32_t len __unused)
|
|||
}
|
||||
|
||||
static void
|
||||
errop_data(uint32_t data __unused, uint32_t len __unused)
|
||||
errop_data(uint32_t data __unused)
|
||||
{
|
||||
|
||||
/* ignore */
|
||||
|
@ -193,7 +191,7 @@ fget_start(uint32_t len)
|
|||
}
|
||||
|
||||
static void
|
||||
fget_data(uint32_t data, uint32_t len __unused)
|
||||
fget_data(uint32_t data)
|
||||
{
|
||||
|
||||
assert(fget_cnt + sizeof(uint32_t) <= sizeof(fget_str));
|
||||
|
@ -348,7 +346,7 @@ fwctl_request_data(uint32_t value)
|
|||
else
|
||||
rinfo.req_size -= sizeof(uint32_t);
|
||||
|
||||
(*rinfo.req_op->op_data)(value, rinfo.req_size);
|
||||
(*rinfo.req_op->op_data)(value);
|
||||
|
||||
if (rinfo.req_size < sizeof(uint32_t)) {
|
||||
fwctl_request_done();
|
||||
|
@ -361,7 +359,6 @@ fwctl_request_data(uint32_t value)
|
|||
static int
|
||||
fwctl_request(uint32_t value)
|
||||
{
|
||||
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
@ -452,12 +449,11 @@ fwctl_reset(void)
|
|||
/* Discard partially-received request. */
|
||||
memset(&rinfo, 0, sizeof(rinfo));
|
||||
break;
|
||||
case IDENT_WAIT:
|
||||
case IDENT_SEND:
|
||||
case IDENT:
|
||||
break;
|
||||
}
|
||||
|
||||
be_state = IDENT_SEND;
|
||||
be_state = IDENT;
|
||||
ident_idx = 0;
|
||||
}
|
||||
|
||||
|
@ -473,7 +469,7 @@ fwctl_inb(void)
|
|||
retval = 0xff;
|
||||
|
||||
switch (be_state) {
|
||||
case IDENT_SEND:
|
||||
case IDENT:
|
||||
retval = sig[ident_idx++];
|
||||
if (ident_idx >= sizeof(sig))
|
||||
be_state = REQ;
|
||||
|
@ -581,5 +577,5 @@ fwctl_init(void)
|
|||
ops[OP_GET_LEN] = &fgetlen_info;
|
||||
ops[OP_GET] = &fgetval_info;
|
||||
|
||||
be_state = IDENT_WAIT;
|
||||
be_state = IDENT;
|
||||
}
|
|
@ -38,7 +38,6 @@
|
|||
* Copyright 2020 Oxide Computer Company
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
|
@ -57,7 +57,7 @@ typedef int (*inout_func_t)(struct vmctx *ctx, int in, int port,
|
|||
int bytes, uint32_t *eax, void *arg);
|
||||
|
||||
struct inout_port {
|
||||
const char *name;
|
||||
const char *name;
|
||||
int port;
|
||||
int size;
|
||||
int flags;
|
|
@ -27,7 +27,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
@ -35,6 +34,7 @@
|
|||
#include <machine/vmm.h>
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "bootrom.h"
|
||||
#include "ioapic.h"
|
||||
#include "pci_emul.h"
|
||||
#include "pci_lpc.h"
|
||||
|
@ -74,7 +74,7 @@ ioapic_pci_alloc_irq(struct pci_devinst *pi)
|
|||
|
||||
if (pci_pins == 0)
|
||||
return (-1);
|
||||
if (lpc_bootrom()) {
|
||||
if (bootrom_boot()) {
|
||||
/* For external bootrom use fixed mapping. */
|
||||
return (16 + (4 + pi->pi_slot + pi->pi_lintr.pin) % 8);
|
||||
}
|
|
@ -24,7 +24,6 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/errno.h>
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
|
@ -31,7 +31,6 @@
|
|||
* Copyright 2018 Joyent, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/vmm.h>
|
||||
|
@ -74,7 +73,7 @@ static struct pci_devinst *lpc_bridge;
|
|||
|
||||
#define LPC_UART_NUM 4
|
||||
static struct lpc_uart_softc {
|
||||
struct uart_softc *uart_softc;
|
||||
struct uart_ns16550_softc *uart_softc;
|
||||
int iobase;
|
||||
int irq;
|
||||
int enabled;
|
||||
|
@ -109,7 +108,7 @@ lpc_device_parse(const char *opts)
|
|||
if (romfile == NULL) {
|
||||
errx(4, "invalid bootrom option \"%s\"", opts);
|
||||
}
|
||||
set_config_value("lpc.bootrom", romfile);
|
||||
set_config_value("bootrom", romfile);
|
||||
|
||||
varfile = strsep(&str, ",");
|
||||
if (varfile == NULL) {
|
||||
|
@ -117,7 +116,7 @@ lpc_device_parse(const char *opts)
|
|||
goto done;
|
||||
}
|
||||
if (strchr(varfile, '=') == NULL) {
|
||||
set_config_value("lpc.bootvars", varfile);
|
||||
set_config_value("bootvars", varfile);
|
||||
} else {
|
||||
/* varfile doesn't exist, it's another config
|
||||
* option */
|
||||
|
@ -187,13 +186,6 @@ lpc_print_supported_devices(void)
|
|||
printf("%s\n", pctestdev_getname());
|
||||
}
|
||||
|
||||
const char *
|
||||
lpc_bootrom(void)
|
||||
{
|
||||
|
||||
return (get_config_value("lpc.bootrom"));
|
||||
}
|
||||
|
||||
const char *
|
||||
lpc_fwcfg(void)
|
||||
{
|
||||
|
@ -231,31 +223,39 @@ lpc_uart_io_handler(struct vmctx *ctx __unused, int in,
|
|||
switch (bytes) {
|
||||
case 1:
|
||||
if (in)
|
||||
*eax = uart_read(sc->uart_softc, offset);
|
||||
*eax = uart_ns16550_read(sc->uart_softc, offset);
|
||||
else
|
||||
uart_write(sc->uart_softc, offset, *eax);
|
||||
uart_ns16550_write(sc->uart_softc, offset, *eax);
|
||||
break;
|
||||
case 2:
|
||||
if (in) {
|
||||
*eax = uart_read(sc->uart_softc, offset);
|
||||
*eax |= uart_read(sc->uart_softc, offset + 1) << 8;
|
||||
*eax = uart_ns16550_read(sc->uart_softc, offset);
|
||||
*eax |=
|
||||
uart_ns16550_read(sc->uart_softc, offset + 1) << 8;
|
||||
} else {
|
||||
uart_write(sc->uart_softc, offset, *eax);
|
||||
uart_write(sc->uart_softc, offset + 1, *eax >> 8);
|
||||
uart_ns16550_write(sc->uart_softc, offset, *eax);
|
||||
uart_ns16550_write(sc->uart_softc, offset + 1,
|
||||
*eax >> 8);
|
||||
}
|
||||
break;
|
||||
#ifndef __FreeBSD__
|
||||
case 4:
|
||||
if (in) {
|
||||
*eax = uart_read(sc->uart_softc, offset);
|
||||
*eax |= uart_read(sc->uart_softc, offset + 1) << 8;
|
||||
*eax |= uart_read(sc->uart_softc, offset + 2) << 16;
|
||||
*eax |= uart_read(sc->uart_softc, offset + 3) << 24;
|
||||
*eax = uart_ns16550_read(sc->uart_softc, offset);
|
||||
*eax |= uart_ns16550_read(sc->uart_softc,
|
||||
offset + 1) << 8;
|
||||
*eax |= uart_ns16550_read(sc->uart_softc,
|
||||
offset + 2) << 16;
|
||||
*eax |= uart_ns16550_read(sc->uart_softc,
|
||||
offset + 3) << 24;
|
||||
} else {
|
||||
uart_write(sc->uart_softc, offset, *eax);
|
||||
uart_write(sc->uart_softc, offset + 1, *eax >> 8);
|
||||
uart_write(sc->uart_softc, offset + 2, *eax >> 16);
|
||||
uart_write(sc->uart_softc, offset + 3, *eax >> 24);
|
||||
uart_ns16550_write(sc->uart_softc, offset, *eax);
|
||||
uart_ns16550_write(sc->uart_softc,
|
||||
offset + 1, *eax >> 8);
|
||||
uart_ns16550_write(sc->uart_softc,
|
||||
offset + 2, *eax >> 16);
|
||||
uart_ns16550_write(sc->uart_softc,
|
||||
offset + 3, *eax >> 24);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
@ -274,22 +274,6 @@ lpc_init(struct vmctx *ctx)
|
|||
const char *backend, *name;
|
||||
char *node_name;
|
||||
int unit, error;
|
||||
const nvlist_t *nvl;
|
||||
|
||||
nvl = find_config_node("lpc");
|
||||
#ifndef __FreeBSD__
|
||||
if (nvl != NULL && nvlist_exists((nvlist_t *)nvl, "bootrom")) {
|
||||
error = bootrom_loadrom(ctx, nvl);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
#else
|
||||
if (nvl != NULL && nvlist_exists(nvl, "bootrom")) {
|
||||
error = bootrom_loadrom(ctx, nvl);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* COM1 and COM2 */
|
||||
for (unit = 0; unit < LPC_UART_NUM; unit++) {
|
||||
|
@ -303,13 +287,14 @@ lpc_init(struct vmctx *ctx)
|
|||
}
|
||||
pci_irq_reserve(sc->irq);
|
||||
|
||||
sc->uart_softc = uart_init(lpc_uart_intr_assert,
|
||||
sc->uart_softc = uart_ns16550_init(lpc_uart_intr_assert,
|
||||
lpc_uart_intr_deassert, sc);
|
||||
|
||||
asprintf(&node_name, "lpc.%s.path", name);
|
||||
backend = get_config_value(node_name);
|
||||
free(node_name);
|
||||
if (uart_set_backend(sc->uart_softc, backend) != 0) {
|
||||
if (backend != NULL &&
|
||||
uart_ns16550_tty_open(sc->uart_softc, backend) != 0) {
|
||||
EPRINTLN("Unable to initialize backend '%s' "
|
||||
"for LPC device %s", backend, name);
|
||||
return (-1);
|
||||
|
@ -318,7 +303,7 @@ lpc_init(struct vmctx *ctx)
|
|||
bzero(&iop, sizeof(struct inout_port));
|
||||
iop.name = name;
|
||||
iop.port = sc->iobase;
|
||||
iop.size = UART_IO_BAR_SIZE;
|
||||
iop.size = UART_NS16550_IO_BAR_SIZE;
|
||||
iop.flags = IOPORT_F_INOUT;
|
||||
iop.handler = lpc_uart_io_handler;
|
||||
iop.arg = sc;
|
||||
|
@ -451,7 +436,7 @@ pci_lpc_uart_dsdt(void)
|
|||
dsdt_line(" Name (_CRS, ResourceTemplate ()");
|
||||
dsdt_line(" {");
|
||||
dsdt_indent(2);
|
||||
dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE);
|
||||
dsdt_fixed_ioport(sc->iobase, UART_NS16550_IO_BAR_SIZE);
|
||||
dsdt_fixed_irq(sc->irq);
|
||||
dsdt_unindent(2);
|
||||
dsdt_line(" })");
|
||||
|
@ -513,15 +498,16 @@ pci_lpc_get_sel(struct pcisel *const sel)
|
|||
sel->pc_dev = slot;
|
||||
sel->pc_func = 0;
|
||||
|
||||
if (read_config(sel, PCIR_HDRTYPE, 1) & PCIM_MFDEV)
|
||||
if (pci_host_read_config(sel, PCIR_HDRTYPE, 1) & PCIM_MFDEV)
|
||||
max_func = PCI_FUNCMAX;
|
||||
|
||||
for (uint8_t func = 0; func <= max_func; ++func) {
|
||||
sel->pc_func = func;
|
||||
|
||||
if ((read_config(sel, PCIR_CLASS, 1) == PCIC_BRIDGE) &&
|
||||
(read_config(sel, PCIR_SUBCLASS, 1) ==
|
||||
PCIS_BRIDGE_ISA)) {
|
||||
if (pci_host_read_config(sel, PCIR_CLASS, 1) ==
|
||||
PCIC_BRIDGE &&
|
||||
pci_host_read_config(sel, PCIR_SUBCLASS, 1) ==
|
||||
PCIS_BRIDGE_ISA) {
|
||||
return (0);
|
||||
}
|
||||
}
|
|
@ -69,7 +69,6 @@ int lpc_device_parse(const char *opt);
|
|||
void lpc_print_supported_devices(void);
|
||||
char *lpc_pirq_name(int pin);
|
||||
void lpc_pirq_routed(void);
|
||||
const char *lpc_bootrom(void);
|
||||
const char *lpc_fwcfg(void);
|
||||
|
||||
#endif
|
||||
#endif /* _LPC_H_ */
|
|
@ -31,7 +31,6 @@
|
|||
* Copyright 2020 Oxide Computer Company
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/vmm.h>
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -51,6 +50,7 @@
|
|||
|
||||
/* keyboard device commands */
|
||||
#define PS2KC_RESET_DEV 0xff
|
||||
#define PS2KC_SET_DEFAULTS 0xf6
|
||||
#define PS2KC_DISABLE 0xf5
|
||||
#define PS2KC_ENABLE 0xf4
|
||||
#define PS2KC_SET_TYPEMATIC 0xf3
|
||||
|
@ -298,6 +298,10 @@ ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)
|
|||
fifo_put(sc, PS2KC_ACK);
|
||||
fifo_put(sc, PS2KC_BAT_SUCCESS);
|
||||
break;
|
||||
case PS2KC_SET_DEFAULTS:
|
||||
fifo_reset(sc);
|
||||
fifo_put(sc, PS2KC_ACK);
|
||||
break;
|
||||
case PS2KC_DISABLE:
|
||||
sc->enabled = false;
|
||||
fifo_put(sc, PS2KC_ACK);
|
|
@ -27,7 +27,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -38,7 +38,6 @@
|
|||
* Copyright 2020 Oxide Computer Company
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -66,7 +65,7 @@ spinup_ap_realmode(struct vcpu *newcpu, uint64_t rip)
|
|||
|
||||
/*
|
||||
* Update the %cs and %rip of the guest so that it starts
|
||||
* executing real mode code at at 'vector << 12'.
|
||||
* executing real mode code at 'vector << 12'.
|
||||
*/
|
||||
error = vm_set_register(newcpu, VM_REG_GUEST_RIP, 0);
|
||||
assert(error == 0);
|
|
@ -38,7 +38,6 @@
|
|||
* Copyright 2020 Oxide Computer Company
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/_iovec.h>
|
|
@ -30,7 +30,6 @@
|
|||
* Copyright 2018 Joyent, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
|
|
@ -0,0 +1,635 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2011 NetApp, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*
|
||||
* Copyright 2015 Pluribus Networks Inc.
|
||||
* Copyright 2018 Joyent, Inc.
|
||||
* Copyright 2022 Oxide Computer Company
|
||||
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
#include <sys/cpuset.h>
|
||||
#include <intel/vmcs.h>
|
||||
#endif
|
||||
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <capsicum_helpers.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
#include <sysexits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <machine/vmm.h>
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "bhyverun.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "gdb.h"
|
||||
#include "inout.h"
|
||||
#include "mem.h"
|
||||
#include "spinup_ap.h"
|
||||
#include "vmexit.h"
|
||||
#include "xmsr.h"
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static struct vm_entry *vmentry;
|
||||
|
||||
int
|
||||
vmentry_init(int ncpus)
|
||||
{
|
||||
vmentry = calloc(ncpus, sizeof(*vmentry));
|
||||
return (vmentry == NULL ? -1 : 0);
|
||||
}
|
||||
|
||||
struct vm_entry *
|
||||
vmentry_vcpu(int vcpuid)
|
||||
{
|
||||
return (&vmentry[vcpuid]);
|
||||
}
|
||||
|
||||
static void
|
||||
vmentry_mmio_read(struct vcpu *vcpu, uint64_t gpa, uint8_t bytes, uint64_t data)
|
||||
{
|
||||
struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
|
||||
struct vm_mmio *mmio = &entry->u.mmio;
|
||||
|
||||
assert(entry->cmd == VEC_DEFAULT);
|
||||
|
||||
entry->cmd = VEC_FULFILL_MMIO;
|
||||
mmio->bytes = bytes;
|
||||
mmio->read = 1;
|
||||
mmio->gpa = gpa;
|
||||
mmio->data = data;
|
||||
}
|
||||
|
||||
static void
|
||||
vmentry_mmio_write(struct vcpu *vcpu, uint64_t gpa, uint8_t bytes)
|
||||
{
|
||||
struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
|
||||
struct vm_mmio *mmio = &entry->u.mmio;
|
||||
|
||||
assert(entry->cmd == VEC_DEFAULT);
|
||||
|
||||
entry->cmd = VEC_FULFILL_MMIO;
|
||||
mmio->bytes = bytes;
|
||||
mmio->read = 0;
|
||||
mmio->gpa = gpa;
|
||||
mmio->data = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vmentry_inout_read(struct vcpu *vcpu, uint16_t port, uint8_t bytes,
|
||||
uint32_t data)
|
||||
{
|
||||
struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
|
||||
struct vm_inout *inout = &entry->u.inout;
|
||||
|
||||
assert(entry->cmd == VEC_DEFAULT);
|
||||
|
||||
entry->cmd = VEC_FULFILL_INOUT;
|
||||
inout->bytes = bytes;
|
||||
inout->flags = INOUT_IN;
|
||||
inout->port = port;
|
||||
inout->eax = data;
|
||||
}
|
||||
|
||||
static void
|
||||
vmentry_inout_write(struct vcpu *vcpu, uint16_t port, uint8_t bytes)
|
||||
{
|
||||
struct vm_entry *entry = &vmentry[vcpu_id(vcpu)];
|
||||
struct vm_inout *inout = &entry->u.inout;
|
||||
|
||||
assert(entry->cmd == VEC_DEFAULT);
|
||||
|
||||
entry->cmd = VEC_FULFILL_INOUT;
|
||||
inout->bytes = bytes;
|
||||
inout->flags = 0;
|
||||
inout->port = port;
|
||||
inout->eax = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
void
|
||||
vm_inject_fault(struct vcpu *vcpu, int vector, int errcode_valid,
|
||||
int errcode)
|
||||
{
|
||||
int error, restart_instruction;
|
||||
|
||||
restart_instruction = 1;
|
||||
|
||||
error = vm_inject_exception(vcpu, vector, errcode_valid, errcode,
|
||||
restart_instruction);
|
||||
assert(error == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
vmexit_inout(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
int error;
|
||||
struct vm_inout inout;
|
||||
bool in;
|
||||
uint8_t bytes;
|
||||
|
||||
inout = vme->u.inout;
|
||||
in = (inout.flags & INOUT_IN) != 0;
|
||||
bytes = inout.bytes;
|
||||
|
||||
error = emulate_inout(ctx, vcpu, &inout);
|
||||
if (error) {
|
||||
EPRINTLN("Unhandled %s%c 0x%04x at 0x%lx",
|
||||
in ? "in" : "out",
|
||||
bytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'),
|
||||
inout.port, vme->rip);
|
||||
return (VMEXIT_ABORT);
|
||||
} else {
|
||||
/*
|
||||
* Communicate the status of the inout operation back to the
|
||||
* in-kernel instruction emulation.
|
||||
*/
|
||||
if (in) {
|
||||
vmentry_inout_read(vcpu, inout.port, bytes, inout.eax);
|
||||
} else {
|
||||
vmentry_inout_write(vcpu, inout.port, bytes);
|
||||
}
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_rdmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
uint64_t val;
|
||||
uint32_t eax, edx;
|
||||
int error;
|
||||
|
||||
val = 0;
|
||||
error = emulate_rdmsr(vcpu, vme->u.msr.code, &val);
|
||||
if (error != 0) {
|
||||
EPRINTLN("rdmsr to register %#x on vcpu %d",
|
||||
vme->u.msr.code, vcpu_id(vcpu));
|
||||
if (get_config_bool("x86.strictmsr")) {
|
||||
vm_inject_gp(vcpu);
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
}
|
||||
|
||||
eax = val;
|
||||
error = vm_set_register(vcpu, VM_REG_GUEST_RAX, eax);
|
||||
assert(error == 0);
|
||||
|
||||
edx = val >> 32;
|
||||
error = vm_set_register(vcpu, VM_REG_GUEST_RDX, edx);
|
||||
assert(error == 0);
|
||||
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_wrmsr(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = emulate_wrmsr(vcpu, vme->u.msr.code, vme->u.msr.wval);
|
||||
if (error != 0) {
|
||||
EPRINTLN("wrmsr to register %#x(%#lx) on vcpu %d",
|
||||
vme->u.msr.code, vme->u.msr.wval, vcpu_id(vcpu));
|
||||
if (get_config_bool("x86.strictmsr")) {
|
||||
vm_inject_gp(vcpu);
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
}
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static const char * const vmx_exit_reason_desc[] = {
|
||||
[EXIT_REASON_EXCEPTION] = "Exception or non-maskable interrupt (NMI)",
|
||||
[EXIT_REASON_EXT_INTR] = "External interrupt",
|
||||
[EXIT_REASON_TRIPLE_FAULT] = "Triple fault",
|
||||
[EXIT_REASON_INIT] = "INIT signal",
|
||||
[EXIT_REASON_SIPI] = "Start-up IPI (SIPI)",
|
||||
[EXIT_REASON_IO_SMI] = "I/O system-management interrupt (SMI)",
|
||||
[EXIT_REASON_SMI] = "Other SMI",
|
||||
[EXIT_REASON_INTR_WINDOW] = "Interrupt window",
|
||||
[EXIT_REASON_NMI_WINDOW] = "NMI window",
|
||||
[EXIT_REASON_TASK_SWITCH] = "Task switch",
|
||||
[EXIT_REASON_CPUID] = "CPUID",
|
||||
[EXIT_REASON_GETSEC] = "GETSEC",
|
||||
[EXIT_REASON_HLT] = "HLT",
|
||||
[EXIT_REASON_INVD] = "INVD",
|
||||
[EXIT_REASON_INVLPG] = "INVLPG",
|
||||
[EXIT_REASON_RDPMC] = "RDPMC",
|
||||
[EXIT_REASON_RDTSC] = "RDTSC",
|
||||
[EXIT_REASON_RSM] = "RSM",
|
||||
[EXIT_REASON_VMCALL] = "VMCALL",
|
||||
[EXIT_REASON_VMCLEAR] = "VMCLEAR",
|
||||
[EXIT_REASON_VMLAUNCH] = "VMLAUNCH",
|
||||
[EXIT_REASON_VMPTRLD] = "VMPTRLD",
|
||||
[EXIT_REASON_VMPTRST] = "VMPTRST",
|
||||
[EXIT_REASON_VMREAD] = "VMREAD",
|
||||
[EXIT_REASON_VMRESUME] = "VMRESUME",
|
||||
[EXIT_REASON_VMWRITE] = "VMWRITE",
|
||||
[EXIT_REASON_VMXOFF] = "VMXOFF",
|
||||
[EXIT_REASON_VMXON] = "VMXON",
|
||||
[EXIT_REASON_CR_ACCESS] = "Control-register accesses",
|
||||
[EXIT_REASON_DR_ACCESS] = "MOV DR",
|
||||
[EXIT_REASON_INOUT] = "I/O instruction",
|
||||
[EXIT_REASON_RDMSR] = "RDMSR",
|
||||
[EXIT_REASON_WRMSR] = "WRMSR",
|
||||
[EXIT_REASON_INVAL_VMCS] =
|
||||
"VM-entry failure due to invalid guest state",
|
||||
[EXIT_REASON_INVAL_MSR] = "VM-entry failure due to MSR loading",
|
||||
[EXIT_REASON_MWAIT] = "MWAIT",
|
||||
[EXIT_REASON_MTF] = "Monitor trap flag",
|
||||
[EXIT_REASON_MONITOR] = "MONITOR",
|
||||
[EXIT_REASON_PAUSE] = "PAUSE",
|
||||
[EXIT_REASON_MCE_DURING_ENTRY] =
|
||||
"VM-entry failure due to machine-check event",
|
||||
[EXIT_REASON_TPR] = "TPR below threshold",
|
||||
[EXIT_REASON_APIC_ACCESS] = "APIC access",
|
||||
[EXIT_REASON_VIRTUALIZED_EOI] = "Virtualized EOI",
|
||||
[EXIT_REASON_GDTR_IDTR] = "Access to GDTR or IDTR",
|
||||
[EXIT_REASON_LDTR_TR] = "Access to LDTR or TR",
|
||||
[EXIT_REASON_EPT_FAULT] = "EPT violation",
|
||||
[EXIT_REASON_EPT_MISCONFIG] = "EPT misconfiguration",
|
||||
[EXIT_REASON_INVEPT] = "INVEPT",
|
||||
[EXIT_REASON_RDTSCP] = "RDTSCP",
|
||||
[EXIT_REASON_VMX_PREEMPT] = "VMX-preemption timer expired",
|
||||
[EXIT_REASON_INVVPID] = "INVVPID",
|
||||
[EXIT_REASON_WBINVD] = "WBINVD",
|
||||
[EXIT_REASON_XSETBV] = "XSETBV",
|
||||
[EXIT_REASON_APIC_WRITE] = "APIC write",
|
||||
[EXIT_REASON_RDRAND] = "RDRAND",
|
||||
[EXIT_REASON_INVPCID] = "INVPCID",
|
||||
[EXIT_REASON_VMFUNC] = "VMFUNC",
|
||||
[EXIT_REASON_ENCLS] = "ENCLS",
|
||||
[EXIT_REASON_RDSEED] = "RDSEED",
|
||||
[EXIT_REASON_PM_LOG_FULL] = "Page-modification log full",
|
||||
[EXIT_REASON_XSAVES] = "XSAVES",
|
||||
[EXIT_REASON_XRSTORS] = "XRSTORS"
|
||||
};
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int
|
||||
vmexit_run_state(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
|
||||
struct vm_exit *vme __unused)
|
||||
{
|
||||
/*
|
||||
* Run-state transitions (INIT, SIPI, etc) are handled in-kernel, so an
|
||||
* exit to userspace with that code is not expected.
|
||||
*/
|
||||
fprintf(stderr, "unexpected run-state VM exit");
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_paging(struct vmctx *ctx __unused, struct vcpu *vcpu,
|
||||
struct vm_exit *vme)
|
||||
{
|
||||
fprintf(stderr, "vm exit[%d]\n", vcpu_id(vcpu));
|
||||
fprintf(stderr, "\treason\t\tPAGING\n");
|
||||
fprintf(stderr, "\trip\t\t0x%016lx\n", vme->rip);
|
||||
fprintf(stderr, "\tgpa\t\t0x%016lx\n", vme->u.paging.gpa);
|
||||
fprintf(stderr, "\tfault_type\t\t%d\n", vme->u.paging.fault_type);
|
||||
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define DEBUG_EPT_MISCONFIG
|
||||
#else
|
||||
/* EPT misconfig debugging not possible now that raw VMCS access is gone */
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_EPT_MISCONFIG
|
||||
#define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400
|
||||
|
||||
static uint64_t ept_misconfig_gpa, ept_misconfig_pte[4];
|
||||
static int ept_misconfig_ptenum;
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
vmexit_vmx_desc(uint32_t exit_reason)
|
||||
{
|
||||
|
||||
if (exit_reason >= nitems(vmx_exit_reason_desc) ||
|
||||
vmx_exit_reason_desc[exit_reason] == NULL)
|
||||
return ("Unknown");
|
||||
return (vmx_exit_reason_desc[exit_reason]);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_vmx(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
|
||||
EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
|
||||
EPRINTLN("\treason\t\tVMX");
|
||||
EPRINTLN("\trip\t\t0x%016lx", vme->rip);
|
||||
EPRINTLN("\tinst_length\t%d", vme->inst_length);
|
||||
EPRINTLN("\tstatus\t\t%d", vme->u.vmx.status);
|
||||
EPRINTLN("\texit_reason\t%u (%s)", vme->u.vmx.exit_reason,
|
||||
vmexit_vmx_desc(vme->u.vmx.exit_reason));
|
||||
EPRINTLN("\tqualification\t0x%016lx",
|
||||
vme->u.vmx.exit_qualification);
|
||||
EPRINTLN("\tinst_type\t\t%d", vme->u.vmx.inst_type);
|
||||
EPRINTLN("\tinst_error\t\t%d", vme->u.vmx.inst_error);
|
||||
#ifdef DEBUG_EPT_MISCONFIG
|
||||
if (vme->u.vmx.exit_reason == EXIT_REASON_EPT_MISCONFIG) {
|
||||
vm_get_register(vcpu,
|
||||
VMCS_IDENT(VMCS_GUEST_PHYSICAL_ADDRESS),
|
||||
&ept_misconfig_gpa);
|
||||
vm_get_gpa_pmap(ctx, ept_misconfig_gpa, ept_misconfig_pte,
|
||||
&ept_misconfig_ptenum);
|
||||
EPRINTLN("\tEPT misconfiguration:");
|
||||
EPRINTLN("\t\tGPA: %#lx", ept_misconfig_gpa);
|
||||
EPRINTLN("\t\tPTE(%d): %#lx %#lx %#lx %#lx",
|
||||
ept_misconfig_ptenum, ept_misconfig_pte[0],
|
||||
ept_misconfig_pte[1], ept_misconfig_pte[2],
|
||||
ept_misconfig_pte[3]);
|
||||
}
|
||||
#endif /* DEBUG_EPT_MISCONFIG */
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_svm(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
EPRINTLN("vm exit[%d]", vcpu_id(vcpu));
|
||||
EPRINTLN("\treason\t\tSVM");
|
||||
EPRINTLN("\trip\t\t0x%016lx", vme->rip);
|
||||
EPRINTLN("\tinst_length\t%d", vme->inst_length);
|
||||
EPRINTLN("\texitcode\t%#lx", vme->u.svm.exitcode);
|
||||
EPRINTLN("\texitinfo1\t%#lx", vme->u.svm.exitinfo1);
|
||||
EPRINTLN("\texitinfo2\t%#lx", vme->u.svm.exitinfo2);
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_bogus(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
|
||||
struct vm_exit *vme)
|
||||
{
|
||||
|
||||
assert(vme->inst_length == 0);
|
||||
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_hlt(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
|
||||
struct vm_exit *vme __unused)
|
||||
{
|
||||
|
||||
/*
|
||||
* Just continue execution with the next instruction. We use
|
||||
* the HLT VM exit as a way to be friendly with the host
|
||||
* scheduler.
|
||||
*/
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_pause(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
|
||||
struct vm_exit *vme __unused)
|
||||
{
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_mtrap(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
|
||||
assert(vme->inst_length == 0);
|
||||
|
||||
gdb_cpu_mtrap(vcpu);
|
||||
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_inst_emul(struct vmctx *ctx __unused, struct vcpu *vcpu,
|
||||
struct vm_exit *vme)
|
||||
{
|
||||
uint8_t i, valid;
|
||||
|
||||
fprintf(stderr, "Failed to emulate instruction sequence ");
|
||||
|
||||
valid = vme->u.inst_emul.num_valid;
|
||||
if (valid != 0) {
|
||||
assert(valid <= sizeof (vme->u.inst_emul.inst));
|
||||
fprintf(stderr, "[");
|
||||
for (i = 0; i < valid; i++) {
|
||||
if (i == 0) {
|
||||
fprintf(stderr, "%02x",
|
||||
vme->u.inst_emul.inst[i]);
|
||||
} else {
|
||||
fprintf(stderr, ", %02x",
|
||||
vme->u.inst_emul.inst[i]);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "] ");
|
||||
}
|
||||
fprintf(stderr, "@ %rip = %x\n", vme->rip);
|
||||
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static int
|
||||
vmexit_mmio(struct vmctx *ctx __unused, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
int err;
|
||||
struct vm_mmio mmio;
|
||||
bool is_read;
|
||||
|
||||
mmio = vme->u.mmio;
|
||||
is_read = (mmio.read != 0);
|
||||
|
||||
err = emulate_mem(vcpu, &mmio);
|
||||
|
||||
if (err == ESRCH) {
|
||||
fprintf(stderr, "Unhandled memory access to 0x%lx\n", mmio.gpa);
|
||||
|
||||
/*
|
||||
* Access to non-existent physical addresses is not likely to
|
||||
* result in fatal errors on hardware machines, but rather reads
|
||||
* of all-ones or discarded-but-acknowledged writes.
|
||||
*/
|
||||
mmio.data = ~0UL;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (err == 0) {
|
||||
if (is_read) {
|
||||
vmentry_mmio_read(vcpu, mmio.gpa, mmio.bytes,
|
||||
mmio.data);
|
||||
} else {
|
||||
vmentry_mmio_write(vcpu, mmio.gpa, mmio.bytes);
|
||||
}
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unhandled mmio error to 0x%lx: %d\n", mmio.gpa, err);
|
||||
return (VMEXIT_ABORT);
|
||||
}
|
||||
#endif /* !__FreeBSD__ */
|
||||
|
||||
static int
|
||||
vmexit_suspend(struct vmctx *ctx, struct vcpu *vcpu, struct vm_exit *vme)
|
||||
{
|
||||
enum vm_suspend_how how;
|
||||
int vcpuid = vcpu_id(vcpu);
|
||||
|
||||
how = vme->u.suspended.how;
|
||||
|
||||
fbsdrun_deletecpu(vcpuid);
|
||||
|
||||
switch (how) {
|
||||
case VM_SUSPEND_RESET:
|
||||
exit(0);
|
||||
case VM_SUSPEND_POWEROFF:
|
||||
if (get_config_bool_default("destroy_on_poweroff", false))
|
||||
vm_destroy(ctx);
|
||||
exit(1);
|
||||
case VM_SUSPEND_HALT:
|
||||
exit(2);
|
||||
case VM_SUSPEND_TRIPLEFAULT:
|
||||
exit(3);
|
||||
default:
|
||||
EPRINTLN("vmexit_suspend: invalid reason %d", how);
|
||||
exit(100);
|
||||
}
|
||||
return (0); /* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_debug(struct vmctx *ctx __unused, struct vcpu *vcpu,
|
||||
struct vm_exit *vme __unused)
|
||||
{
|
||||
gdb_cpu_suspend(vcpu);
|
||||
/*
|
||||
* Sleep for a short period to avoid chewing up the CPU in the
|
||||
* window between activation of the vCPU thread and the STARTUP IPI.
|
||||
*/
|
||||
usleep(1000);
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
static int
|
||||
vmexit_breakpoint(struct vmctx *ctx __unused, struct vcpu *vcpu,
|
||||
struct vm_exit *vme)
|
||||
{
|
||||
|
||||
gdb_cpu_breakpoint(vcpu, vme);
|
||||
return (VMEXIT_CONTINUE);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static int
|
||||
vmexit_ipi(struct vmctx *ctx __unused, struct vcpu *vcpu __unused,
|
||||
struct vm_exit *vme)
|
||||
{
|
||||
int error = -1;
|
||||
int i;
|
||||
switch (vme->u.ipi.mode) {
|
||||
case APIC_DELMODE_INIT:
|
||||
CPU_FOREACH_ISSET(i, &vme->u.ipi.dmask) {
|
||||
error = vm_suspend_cpu(vcpu_info[i].vcpu);
|
||||
if (error) {
|
||||
warnx("%s: failed to suspend cpu %d\n",
|
||||
__func__, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case APIC_DELMODE_STARTUP:
|
||||
CPU_FOREACH_ISSET(i, &vme->u.ipi.dmask) {
|
||||
spinup_ap(vcpu_info[i].vcpu,
|
||||
vme->u.ipi.vector << PAGE_SHIFT);
|
||||
}
|
||||
error = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
#endif
|
||||
|
||||
const vmexit_handler_t vmexit_handlers[VM_EXITCODE_MAX] = {
|
||||
[VM_EXITCODE_INOUT] = vmexit_inout,
|
||||
#ifndef __FreeBSD__
|
||||
[VM_EXITCODE_MMIO] = vmexit_mmio,
|
||||
#endif
|
||||
[VM_EXITCODE_VMX] = vmexit_vmx,
|
||||
[VM_EXITCODE_SVM] = vmexit_svm,
|
||||
[VM_EXITCODE_BOGUS] = vmexit_bogus,
|
||||
[VM_EXITCODE_RDMSR] = vmexit_rdmsr,
|
||||
[VM_EXITCODE_WRMSR] = vmexit_wrmsr,
|
||||
[VM_EXITCODE_MTRAP] = vmexit_mtrap,
|
||||
[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
|
||||
#ifndef __FreeBSD__
|
||||
[VM_EXITCODE_RUN_STATE] = vmexit_run_state,
|
||||
[VM_EXITCODE_PAGING] = vmexit_paging,
|
||||
#endif
|
||||
[VM_EXITCODE_SUSPENDED] = vmexit_suspend,
|
||||
[VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch,
|
||||
[VM_EXITCODE_DEBUG] = vmexit_debug,
|
||||
[VM_EXITCODE_BPT] = vmexit_breakpoint,
|
||||
#ifdef __FreeBSD__
|
||||
[VM_EXITCODE_IPI] = vmexit_ipi,
|
||||
#endif
|
||||
[VM_EXITCODE_HLT] = vmexit_hlt,
|
||||
[VM_EXITCODE_PAUSE] = vmexit_pause,
|
||||
};
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -34,12 +33,14 @@
|
|||
#include <machine/vmm.h>
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#include <vmmapi.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "xmsr.h"
|
||||
|
||||
|
@ -255,7 +256,7 @@ init_msr(void)
|
|||
cpu_vendor_intel = 1;
|
||||
} else {
|
||||
EPRINTLN("Unknown cpu vendor \"%s\"", cpu_vendor);
|
||||
error = -1;
|
||||
error = ENOENT;
|
||||
}
|
||||
return (error);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -36,7 +36,6 @@
|
|||
* above the MPTable.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
|
@ -327,7 +326,7 @@ basl_load(struct vmctx *ctx, int fd)
|
|||
|
||||
addr = calloc(1, sb.st_size);
|
||||
if (addr == NULL)
|
||||
return (EFAULT);
|
||||
return (ENOMEM);
|
||||
|
||||
if (read(fd, addr, sb.st_size) < 0)
|
||||
return (errno);
|
||||
|
@ -339,6 +338,7 @@ basl_load(struct vmctx *ctx, int fd)
|
|||
BASL_EXEC(basl_table_create(&table, ctx, name, BASL_TABLE_ALIGNMENT));
|
||||
BASL_EXEC(basl_table_append_bytes(table, addr, sb.st_size));
|
||||
|
||||
free(addr);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <sys/capsicum.h>
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -0,0 +1,881 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2011 NetApp, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* This file and its contents are supplied under the terms of the
|
||||
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
* You may only use this file in accordance with the terms of version
|
||||
* 1.0 of the CDDL.
|
||||
*
|
||||
* A full copy of the text of the CDDL should have accompanied this
|
||||
* source. A copy of the CDDL is also available via the Internet at
|
||||
* http://www.illumos.org/license/CDDL.
|
||||
*
|
||||
* Copyright 2015 Pluribus Networks Inc.
|
||||
* Copyright 2018 Joyent, Inc.
|
||||
* Copyright 2022 Oxide Computer Company
|
||||
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <sys/capsicum.h>
|
||||
#endif
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <amd64/vmm/intel/vmcs.h>
|
||||
#else
|
||||
#include <sys/cpuset.h>
|
||||
#include <intel/vmcs.h>
|
||||
#endif
|
||||
|
||||
#include <machine/atomic.h>
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <capsicum_helpers.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
#include <sysexits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <machine/vmm.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <machine/vmm_dev.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <machine/vmm_instruction_emul.h>
|
||||
#endif
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "acpi.h"
|
||||
#include "bhyverun.h"
|
||||
#include "bootrom.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "gdb.h"
|
||||
#include "ioapic.h"
|
||||
#include "mem.h"
|
||||
#include "mevent.h"
|
||||
#include "pci_emul.h"
|
||||
#include "pci_lpc.h"
|
||||
#include "qemu_fwcfg.h"
|
||||
#include "tpm_device.h"
|
||||
#include "spinup_ap.h"
|
||||
#include "vmgenc.h"
|
||||
#include "vmexit.h"
|
||||
#ifndef __FreeBSD__
|
||||
#include "smbiostbl.h"
|
||||
#include "privileges.h"
|
||||
#endif
|
||||
|
||||
#define MB (1024UL * 1024)
|
||||
#define GB (1024UL * MB)
|
||||
|
||||
int guest_ncpus;
|
||||
uint16_t cpu_cores, cpu_sockets, cpu_threads;
|
||||
|
||||
int raw_stdio = 0;
|
||||
|
||||
static const int BSP = 0;
|
||||
|
||||
static cpuset_t cpumask;
|
||||
|
||||
static void vm_loop(struct vmctx *ctx, struct vcpu *vcpu);
|
||||
|
||||
static struct vcpu_info {
|
||||
struct vmctx *ctx;
|
||||
struct vcpu *vcpu;
|
||||
int vcpuid;
|
||||
} *vcpu_info;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static cpuset_t **vcpumap;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* XXX This parser is known to have the following issues:
|
||||
* 1. It accepts null key=value tokens ",," as setting "cpus" to an
|
||||
* empty string.
|
||||
*
|
||||
* The acceptance of a null specification ('-c ""') is by design to match the
|
||||
* manual page syntax specification, this results in a topology of 1 vCPU.
|
||||
*/
|
||||
int
|
||||
bhyve_topology_parse(const char *opt)
|
||||
{
|
||||
char *cp, *str, *tofree;
|
||||
|
||||
if (*opt == '\0') {
|
||||
set_config_value("sockets", "1");
|
||||
set_config_value("cores", "1");
|
||||
set_config_value("threads", "1");
|
||||
set_config_value("cpus", "1");
|
||||
return (0);
|
||||
}
|
||||
|
||||
tofree = str = strdup(opt);
|
||||
if (str == NULL)
|
||||
errx(4, "Failed to allocate memory");
|
||||
|
||||
while ((cp = strsep(&str, ",")) != NULL) {
|
||||
if (strncmp(cp, "cpus=", strlen("cpus=")) == 0)
|
||||
set_config_value("cpus", cp + strlen("cpus="));
|
||||
else if (strncmp(cp, "sockets=", strlen("sockets=")) == 0)
|
||||
set_config_value("sockets", cp + strlen("sockets="));
|
||||
else if (strncmp(cp, "cores=", strlen("cores=")) == 0)
|
||||
set_config_value("cores", cp + strlen("cores="));
|
||||
else if (strncmp(cp, "threads=", strlen("threads=")) == 0)
|
||||
set_config_value("threads", cp + strlen("threads="));
|
||||
else if (strchr(cp, '=') != NULL)
|
||||
goto out;
|
||||
else
|
||||
set_config_value("cpus", cp);
|
||||
}
|
||||
free(tofree);
|
||||
return (0);
|
||||
|
||||
out:
|
||||
free(tofree);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_int_value(const char *key, const char *value, int minval, int maxval)
|
||||
{
|
||||
char *cp;
|
||||
long lval;
|
||||
|
||||
errno = 0;
|
||||
lval = strtol(value, &cp, 0);
|
||||
if (errno != 0 || *cp != '\0' || cp == value || lval < minval ||
|
||||
lval > maxval)
|
||||
errx(4, "Invalid value for %s: '%s'", key, value);
|
||||
return (lval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the sockets, cores, threads, and guest_cpus variables based on
|
||||
* the configured topology.
|
||||
*
|
||||
* The limits of UINT16_MAX are due to the types passed to
|
||||
* vm_set_topology(). vmm.ko may enforce tighter limits.
|
||||
*/
|
||||
static void
|
||||
calc_topology(void)
|
||||
{
|
||||
const char *value;
|
||||
bool explicit_cpus;
|
||||
uint64_t ncpus;
|
||||
|
||||
value = get_config_value("cpus");
|
||||
if (value != NULL) {
|
||||
guest_ncpus = parse_int_value("cpus", value, 1, UINT16_MAX);
|
||||
explicit_cpus = true;
|
||||
} else {
|
||||
guest_ncpus = 1;
|
||||
explicit_cpus = false;
|
||||
}
|
||||
value = get_config_value("cores");
|
||||
if (value != NULL)
|
||||
cpu_cores = parse_int_value("cores", value, 1, UINT16_MAX);
|
||||
else
|
||||
cpu_cores = 1;
|
||||
value = get_config_value("threads");
|
||||
if (value != NULL)
|
||||
cpu_threads = parse_int_value("threads", value, 1, UINT16_MAX);
|
||||
else
|
||||
cpu_threads = 1;
|
||||
value = get_config_value("sockets");
|
||||
if (value != NULL)
|
||||
cpu_sockets = parse_int_value("sockets", value, 1, UINT16_MAX);
|
||||
else
|
||||
cpu_sockets = guest_ncpus;
|
||||
|
||||
/*
|
||||
* Compute sockets * cores * threads avoiding overflow. The
|
||||
* range check above insures these are 16 bit values.
|
||||
*/
|
||||
ncpus = (uint64_t)cpu_sockets * cpu_cores * cpu_threads;
|
||||
if (ncpus > UINT16_MAX)
|
||||
errx(4, "Computed number of vCPUs too high: %ju",
|
||||
(uintmax_t)ncpus);
|
||||
|
||||
if (explicit_cpus) {
|
||||
if (guest_ncpus != (int)ncpus)
|
||||
errx(4, "Topology (%d sockets, %d cores, %d threads) "
|
||||
"does not match %d vCPUs",
|
||||
cpu_sockets, cpu_cores, cpu_threads,
|
||||
guest_ncpus);
|
||||
} else
|
||||
guest_ncpus = ncpus;
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int
|
||||
bhyve_pincpu_parse(const char *opt)
|
||||
{
|
||||
int vcpu, pcpu;
|
||||
const char *value;
|
||||
char *newval;
|
||||
char key[16];
|
||||
|
||||
if (sscanf(opt, "%d:%d", &vcpu, &pcpu) != 2) {
|
||||
fprintf(stderr, "invalid format: %s\n", opt);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (vcpu < 0) {
|
||||
fprintf(stderr, "invalid vcpu '%d'\n", vcpu);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (pcpu < 0 || pcpu >= CPU_SETSIZE) {
|
||||
fprintf(stderr, "hostcpu '%d' outside valid range from "
|
||||
"0 to %d\n", pcpu, CPU_SETSIZE - 1);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
|
||||
value = get_config_value(key);
|
||||
|
||||
if (asprintf(&newval, "%s%s%d", value != NULL ? value : "",
|
||||
value != NULL ? "," : "", pcpu) == -1) {
|
||||
perror("failed to build new cpuset string");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
set_config_value(key, newval);
|
||||
free(newval);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_cpuset(int vcpu, const char *list, cpuset_t *set)
|
||||
{
|
||||
char *cp, *token;
|
||||
int pcpu, start;
|
||||
|
||||
CPU_ZERO(set);
|
||||
start = -1;
|
||||
token = __DECONST(char *, list);
|
||||
for (;;) {
|
||||
pcpu = strtoul(token, &cp, 0);
|
||||
if (cp == token)
|
||||
errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
|
||||
if (pcpu < 0 || pcpu >= CPU_SETSIZE)
|
||||
errx(4, "hostcpu '%d' outside valid range from 0 to %d",
|
||||
pcpu, CPU_SETSIZE - 1);
|
||||
switch (*cp) {
|
||||
case ',':
|
||||
case '\0':
|
||||
if (start >= 0) {
|
||||
if (start > pcpu)
|
||||
errx(4, "Invalid hostcpu range %d-%d",
|
||||
start, pcpu);
|
||||
while (start < pcpu) {
|
||||
CPU_SET(start, set);
|
||||
start++;
|
||||
}
|
||||
start = -1;
|
||||
}
|
||||
CPU_SET(pcpu, set);
|
||||
break;
|
||||
case '-':
|
||||
if (start >= 0)
|
||||
errx(4, "invalid cpuset for vcpu %d: '%s'",
|
||||
vcpu, list);
|
||||
start = pcpu;
|
||||
break;
|
||||
default:
|
||||
errx(4, "invalid cpuset for vcpu %d: '%s'", vcpu, list);
|
||||
}
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
token = cp + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
build_vcpumaps(void)
|
||||
{
|
||||
char key[16];
|
||||
const char *value;
|
||||
int vcpu;
|
||||
|
||||
vcpumap = calloc(guest_ncpus, sizeof(*vcpumap));
|
||||
for (vcpu = 0; vcpu < guest_ncpus; vcpu++) {
|
||||
snprintf(key, sizeof(key), "vcpu.%d.cpuset", vcpu);
|
||||
value = get_config_value(key);
|
||||
if (value == NULL)
|
||||
continue;
|
||||
vcpumap[vcpu] = malloc(sizeof(cpuset_t));
|
||||
if (vcpumap[vcpu] == NULL)
|
||||
err(4, "Failed to allocate cpuset for vcpu %d", vcpu);
|
||||
parse_cpuset(vcpu, value, vcpumap[vcpu]);
|
||||
}
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
void *
|
||||
paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
|
||||
{
|
||||
|
||||
return (vm_map_gpa(ctx, gaddr, len));
|
||||
}
|
||||
|
||||
int
|
||||
fbsdrun_virtio_msix(void)
|
||||
{
|
||||
|
||||
return (get_config_bool_default("virtio_msix", true));
|
||||
}
|
||||
|
||||
struct vcpu *
|
||||
fbsdrun_vcpu(int vcpuid)
|
||||
{
|
||||
return (vcpu_info[vcpuid].vcpu);
|
||||
}
|
||||
|
||||
static void *
|
||||
fbsdrun_start_thread(void *param)
|
||||
{
|
||||
char tname[MAXCOMLEN + 1];
|
||||
struct vcpu_info *vi = param;
|
||||
#ifdef __FreeBSD__
|
||||
int error;
|
||||
#endif
|
||||
|
||||
snprintf(tname, sizeof(tname), "vcpu %d", vi->vcpuid);
|
||||
pthread_set_name_np(pthread_self(), tname);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if (vcpumap[vi->vcpuid] != NULL) {
|
||||
error = pthread_setaffinity_np(pthread_self(),
|
||||
sizeof(cpuset_t), vcpumap[vi->vcpuid]);
|
||||
assert(error == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
gdb_cpu_add(vi->vcpu);
|
||||
|
||||
vm_loop(vi->ctx, vi->vcpu);
|
||||
|
||||
/* not reached */
|
||||
exit(1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
fbsdrun_addcpu(int vcpuid, bool suspend)
|
||||
{
|
||||
struct vcpu_info *vi;
|
||||
pthread_t thr;
|
||||
int error;
|
||||
|
||||
vi = &vcpu_info[vcpuid];
|
||||
|
||||
error = vm_activate_cpu(vi->vcpu);
|
||||
if (error != 0)
|
||||
err(EX_OSERR, "could not activate CPU %d", vi->vcpuid);
|
||||
|
||||
CPU_SET_ATOMIC(vcpuid, &cpumask);
|
||||
|
||||
if (suspend) {
|
||||
error = vm_suspend_cpu(vi->vcpu);
|
||||
assert(error == 0);
|
||||
}
|
||||
|
||||
error = pthread_create(&thr, NULL, fbsdrun_start_thread, vi);
|
||||
assert(error == 0);
|
||||
}
|
||||
|
||||
void
|
||||
fbsdrun_deletecpu(int vcpu)
|
||||
{
|
||||
static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
pthread_mutex_lock(&resetcpu_mtx);
|
||||
if (!CPU_ISSET(vcpu, &cpumask)) {
|
||||
EPRINTLN("Attempting to delete unknown cpu %d", vcpu);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
CPU_CLR(vcpu, &cpumask);
|
||||
|
||||
if (vcpu != BSP) {
|
||||
pthread_cond_signal(&resetcpu_cond);
|
||||
pthread_mutex_unlock(&resetcpu_mtx);
|
||||
pthread_exit(NULL);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
while (!CPU_EMPTY(&cpumask)) {
|
||||
pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
|
||||
}
|
||||
pthread_mutex_unlock(&resetcpu_mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
vm_loop(struct vmctx *ctx, struct vcpu *vcpu)
|
||||
{
|
||||
struct vm_exit vme;
|
||||
int error, rc;
|
||||
enum vm_exitcode exitcode;
|
||||
cpuset_t active_cpus;
|
||||
struct vm_entry *ventry;
|
||||
|
||||
error = vm_active_cpus(ctx, &active_cpus);
|
||||
assert(CPU_ISSET(vcpu_id(vcpu), &active_cpus));
|
||||
|
||||
ventry = vmentry_vcpu(vcpu_id(vcpu));
|
||||
|
||||
while (1) {
|
||||
error = vm_run(vcpu, ventry, &vme);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
if (ventry->cmd != VEC_DEFAULT) {
|
||||
/*
|
||||
* Discard any lingering entry state after it has been
|
||||
* submitted via vm_run().
|
||||
*/
|
||||
bzero(ventry, sizeof (*ventry));
|
||||
}
|
||||
|
||||
exitcode = vme.exitcode;
|
||||
if (exitcode >= VM_EXITCODE_MAX ||
|
||||
vmexit_handlers[exitcode] == NULL) {
|
||||
fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n",
|
||||
exitcode);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
rc = (*vmexit_handlers[exitcode])(ctx, vcpu, &vme);
|
||||
|
||||
switch (rc) {
|
||||
case VMEXIT_CONTINUE:
|
||||
break;
|
||||
case VMEXIT_ABORT:
|
||||
abort();
|
||||
default:
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
EPRINTLN("vm_run error %d, errno %d", error, errno);
|
||||
}
|
||||
|
||||
static int
|
||||
num_vcpus_allowed(struct vmctx *ctx, struct vcpu *vcpu)
|
||||
{
|
||||
uint16_t sockets, cores, threads, maxcpus;
|
||||
#ifdef __FreeBSD__
|
||||
int tmp, error;
|
||||
|
||||
/*
|
||||
* The guest is allowed to spinup more than one processor only if the
|
||||
* UNRESTRICTED_GUEST capability is available.
|
||||
*/
|
||||
error = vm_get_capability(vcpu, VM_CAP_UNRESTRICTED_GUEST, &tmp);
|
||||
if (error != 0)
|
||||
return (1);
|
||||
#else
|
||||
int error;
|
||||
/* Unrestricted Guest is always enabled on illumos */
|
||||
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
error = vm_get_topology(ctx, &sockets, &cores, &threads, &maxcpus);
|
||||
if (error == 0)
|
||||
return (maxcpus);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
static struct vmctx *
|
||||
do_open(const char *vmname)
|
||||
{
|
||||
struct vmctx *ctx;
|
||||
int error;
|
||||
bool reinit, romboot;
|
||||
|
||||
reinit = romboot = false;
|
||||
|
||||
romboot = bootrom_boot();
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
uint64_t create_flags = 0;
|
||||
if (get_config_bool_default("memory.use_reservoir", false)) {
|
||||
create_flags |= VCF_RESERVOIR_MEM;
|
||||
}
|
||||
error = vm_create(vmname, create_flags);
|
||||
#else
|
||||
error = vm_create(vmname);
|
||||
#endif /* __FreeBSD__ */
|
||||
if (error) {
|
||||
if (errno == EEXIST) {
|
||||
if (romboot) {
|
||||
reinit = true;
|
||||
} else {
|
||||
/*
|
||||
* The virtual machine has been setup by the
|
||||
* userspace bootloader.
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
perror("vm_create");
|
||||
exit(4);
|
||||
}
|
||||
} else {
|
||||
if (!romboot) {
|
||||
/*
|
||||
* If the virtual machine was just created then a
|
||||
* bootrom must be configured to boot it.
|
||||
*/
|
||||
fprintf(stderr, "virtual machine cannot be booted\n");
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
ctx = vm_open(vmname);
|
||||
if (ctx == NULL) {
|
||||
perror("vm_open");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
if (vm_limit_rights(ctx) != 0)
|
||||
err(EX_OSERR, "vm_limit_rights");
|
||||
#endif
|
||||
|
||||
if (reinit) {
|
||||
#ifndef __FreeBSD__
|
||||
error = vm_reinit(ctx, 0);
|
||||
#else
|
||||
error = vm_reinit(ctx);
|
||||
#endif
|
||||
if (error) {
|
||||
perror("vm_reinit");
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
error = vm_set_topology(ctx, cpu_sockets, cpu_cores, cpu_threads, 0);
|
||||
if (error)
|
||||
errx(EX_OSERR, "vm_set_topology");
|
||||
return (ctx);
|
||||
}
|
||||
|
||||
bool
|
||||
bhyve_parse_config_option(const char *option)
|
||||
{
|
||||
const char *value;
|
||||
char *path;
|
||||
|
||||
value = strchr(option, '=');
|
||||
if (value == NULL || value[1] == '\0')
|
||||
return (false);
|
||||
path = strndup(option, value - option);
|
||||
if (path == NULL)
|
||||
err(4, "Failed to allocate memory");
|
||||
set_config_value(path, value + 1);
|
||||
free(path);
|
||||
return (true);
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_parse_simple_config_file(const char *path)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line, *cp;
|
||||
size_t linecap;
|
||||
unsigned int lineno;
|
||||
|
||||
fp = fopen(path, "r");
|
||||
if (fp == NULL)
|
||||
err(4, "Failed to open configuration file %s", path);
|
||||
line = NULL;
|
||||
linecap = 0;
|
||||
lineno = 1;
|
||||
for (lineno = 1; getline(&line, &linecap, fp) > 0; lineno++) {
|
||||
if (*line == '#' || *line == '\n')
|
||||
continue;
|
||||
cp = strchr(line, '\n');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
if (!bhyve_parse_config_option(line))
|
||||
errx(4, "%s line %u: invalid config option '%s'", path,
|
||||
lineno, line);
|
||||
}
|
||||
free(line);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void
|
||||
bhyve_parse_gdb_options(const char *opt)
|
||||
{
|
||||
const char *sport;
|
||||
char *colon;
|
||||
|
||||
if (opt[0] == 'w') {
|
||||
set_config_bool("gdb.wait", true);
|
||||
opt++;
|
||||
}
|
||||
|
||||
colon = strrchr(opt, ':');
|
||||
if (colon == NULL) {
|
||||
sport = opt;
|
||||
} else {
|
||||
*colon = '\0';
|
||||
colon++;
|
||||
sport = colon;
|
||||
set_config_value("gdb.address", opt);
|
||||
}
|
||||
|
||||
set_config_value("gdb.port", sport);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int error;
|
||||
int max_vcpus, memflags;
|
||||
struct vcpu *bsp;
|
||||
struct vmctx *ctx;
|
||||
size_t memsize;
|
||||
const char *value, *vmname;
|
||||
|
||||
bhyve_init_config();
|
||||
|
||||
bhyve_optparse(argc, argv);
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 1)
|
||||
bhyve_usage(1);
|
||||
|
||||
if (argc == 1)
|
||||
set_config_value("name", argv[0]);
|
||||
|
||||
vmname = get_config_value("name");
|
||||
if (vmname == NULL)
|
||||
bhyve_usage(1);
|
||||
|
||||
if (get_config_bool_default("config.dump", false)) {
|
||||
dump_config();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
illumos_priv_init();
|
||||
#endif
|
||||
|
||||
calc_topology();
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
build_vcpumaps();
|
||||
#endif
|
||||
|
||||
value = get_config_value("memory.size");
|
||||
error = vm_parse_memsize(value, &memsize);
|
||||
if (error)
|
||||
errx(EX_USAGE, "invalid memsize '%s'", value);
|
||||
|
||||
ctx = do_open(vmname);
|
||||
|
||||
bsp = vm_vcpu_open(ctx, BSP);
|
||||
max_vcpus = num_vcpus_allowed(ctx, bsp);
|
||||
if (guest_ncpus > max_vcpus) {
|
||||
fprintf(stderr, "%d vCPUs requested but only %d available\n",
|
||||
guest_ncpus, max_vcpus);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
bhyve_init_vcpu(bsp);
|
||||
|
||||
/* Allocate per-VCPU resources. */
|
||||
vcpu_info = calloc(guest_ncpus, sizeof(*vcpu_info));
|
||||
for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++) {
|
||||
vcpu_info[vcpuid].ctx = ctx;
|
||||
vcpu_info[vcpuid].vcpuid = vcpuid;
|
||||
if (vcpuid == BSP)
|
||||
vcpu_info[vcpuid].vcpu = bsp;
|
||||
else
|
||||
vcpu_info[vcpuid].vcpu = vm_vcpu_open(ctx, vcpuid);
|
||||
}
|
||||
|
||||
memflags = 0;
|
||||
if (get_config_bool_default("memory.wired", false))
|
||||
memflags |= VM_MEM_F_WIRED;
|
||||
if (get_config_bool_default("memory.guest_in_core", false))
|
||||
memflags |= VM_MEM_F_INCORE;
|
||||
vm_set_memflags(ctx, memflags);
|
||||
#ifdef __FreeBSD__
|
||||
error = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
|
||||
#else
|
||||
int _errno;
|
||||
do {
|
||||
errno = 0;
|
||||
error = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
|
||||
_errno = errno;
|
||||
if (error != 0 && _errno == ENOMEM) {
|
||||
(void) fprintf(stderr, "Unable to allocate memory "
|
||||
"(%llu), retrying in 1 second\n", memsize);
|
||||
sleep(1);
|
||||
}
|
||||
} while (_errno == ENOMEM);
|
||||
#endif
|
||||
if (error) {
|
||||
fprintf(stderr, "Unable to set up memory (%d)\n", errno);
|
||||
exit(4);
|
||||
}
|
||||
|
||||
init_mem(guest_ncpus);
|
||||
init_bootrom(ctx);
|
||||
|
||||
if (bhyve_init_platform(ctx, bsp) != 0)
|
||||
exit(4);
|
||||
|
||||
if (qemu_fwcfg_init(ctx) != 0) {
|
||||
fprintf(stderr, "qemu fwcfg initialization error\n");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
if (qemu_fwcfg_add_file("opt/bhyve/hw.ncpu", sizeof(guest_ncpus),
|
||||
&guest_ncpus) != 0) {
|
||||
fprintf(stderr, "Could not add qemu fwcfg opt/bhyve/hw.ncpu\n");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Exit if a device emulation finds an error in its initialization
|
||||
*/
|
||||
if (init_pci(ctx) != 0) {
|
||||
EPRINTLN("Device emulation initialization error: %s",
|
||||
strerror(errno));
|
||||
exit(4);
|
||||
}
|
||||
if (init_tpm(ctx) != 0) {
|
||||
EPRINTLN("Failed to init TPM device");
|
||||
exit(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize after PCI, to allow a bootrom file to reserve the high
|
||||
* region.
|
||||
*/
|
||||
if (get_config_bool("acpi_tables"))
|
||||
vmgenc_init(ctx);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
init_gdb(ctx);
|
||||
#else
|
||||
if (value != NULL) {
|
||||
int port = atoi(value);
|
||||
|
||||
if (port < 0)
|
||||
init_mdb(ctx);
|
||||
else
|
||||
init_gdb(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bootrom_boot()) {
|
||||
#ifdef __FreeBSD__
|
||||
if (vm_set_capability(bsp, VM_CAP_UNRESTRICTED_GUEST, 1)) {
|
||||
fprintf(stderr, "ROM boot failed: unrestricted guest "
|
||||
"capability not available\n");
|
||||
exit(4);
|
||||
}
|
||||
#else
|
||||
/* Unrestricted Guest is always enabled on illumos */
|
||||
#endif
|
||||
error = vcpu_reset(bsp);
|
||||
assert(error == 0);
|
||||
}
|
||||
|
||||
if (bhyve_init_platform_late(ctx, bsp) != 0)
|
||||
exit(4);
|
||||
|
||||
/*
|
||||
* Change the proc title to include the VM name.
|
||||
*/
|
||||
setproctitle("%s", vmname);
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
caph_cache_catpages();
|
||||
|
||||
if (caph_limit_stdout() == -1 || caph_limit_stderr() == -1)
|
||||
errx(EX_OSERR, "Unable to apply rights for sandbox");
|
||||
|
||||
if (caph_enter() == -1)
|
||||
errx(EX_OSERR, "cap_enter() failed");
|
||||
#endif
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
illumos_priv_lock();
|
||||
#endif
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
if (vmentry_init(guest_ncpus) != 0)
|
||||
err(EX_OSERR, "vmentry_init() failed");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Add all vCPUs.
|
||||
*/
|
||||
for (int vcpuid = 0; vcpuid < guest_ncpus; vcpuid++) {
|
||||
#ifdef __FreeBSD__
|
||||
bool suspend = (vcpuid != BSP);
|
||||
#else
|
||||
bool suspend = vcpuid == BSP &&
|
||||
get_config_bool_default("suspend_at_boot", false);
|
||||
#endif
|
||||
bhyve_start_vcpu(vcpu_info[vcpuid].vcpu, vcpuid == BSP,
|
||||
suspend);
|
||||
}
|
||||
|
||||
/*
|
||||
* Head off to the main event dispatch loop
|
||||
*/
|
||||
mevent_dispatch();
|
||||
|
||||
exit(4);
|
||||
}
|
|
@ -38,12 +38,14 @@
|
|||
* Copyright 2015 Pluribus Networks Inc.
|
||||
*/
|
||||
|
||||
#ifndef _FBSDRUN_H_
|
||||
#define _FBSDRUN_H_
|
||||
#ifndef _BHYVERUN_H_
|
||||
#define _BHYVERUN_H_
|
||||
|
||||
#define VMEXIT_CONTINUE (0)
|
||||
#define VMEXIT_ABORT (-1)
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int guest_ncpus;
|
||||
extern uint16_t cpu_cores, cpu_sockets, cpu_threads;
|
||||
|
||||
|
@ -51,15 +53,35 @@ struct vcpu;
|
|||
struct vmctx;
|
||||
struct vm_exit;
|
||||
|
||||
void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len);
|
||||
extern void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len);
|
||||
|
||||
struct vcpu *fbsdrun_vcpu(int vcpuid);
|
||||
void fbsdrun_addcpu(int vcpuid, bool);
|
||||
void fbsdrun_deletecpu(int vcpuid);
|
||||
|
||||
int fbsdrun_virtio_msix(void);
|
||||
|
||||
int vmexit_task_switch(struct vmctx *, struct vcpu *, struct vm_exit *);
|
||||
typedef int (*vmexit_handler_t)(struct vmctx *, struct vcpu *,
|
||||
struct vm_exit *);
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
struct vcpu_info;
|
||||
void fbsdrun_addcpu(struct vcpu_info *, bool);
|
||||
extern int vmexit_task_switch(struct vmctx *, struct vcpu *, struct vm_exit *);
|
||||
|
||||
/* Interfaces implemented by machine-dependent code. */
|
||||
void bhyve_init_config(void);
|
||||
void bhyve_init_vcpu(struct vcpu *vcpu);
|
||||
void bhyve_start_vcpu(struct vcpu *vcpu, bool bsp, bool suspend);
|
||||
int bhyve_init_platform(struct vmctx *ctx, struct vcpu *bsp);
|
||||
int bhyve_init_platform_late(struct vmctx *ctx, struct vcpu *bsp);
|
||||
void bhyve_optparse(int argc, char **argv);
|
||||
void bhyve_usage(int code);
|
||||
|
||||
/* Interfaces used by command-line option-parsing code. */
|
||||
bool bhyve_parse_config_option(const char *option);
|
||||
void bhyve_parse_simple_config_file(const char *path);
|
||||
void bhyve_parse_gdb_options(const char *opt);
|
||||
#ifdef __FreeBSD__
|
||||
int bhyve_pincpu_parse(const char *opt);
|
||||
#endif
|
||||
int bhyve_topology_parse(const char *opt);
|
||||
|
||||
#endif
|
|
@ -31,7 +31,6 @@
|
|||
* Copyright 2020 Joyent, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
|
@ -119,12 +119,15 @@ bootrom_var_mem_handler(struct vcpu *vcpu __unused, int dir, uint64_t addr,
|
|||
void
|
||||
init_bootrom(struct vmctx *ctx)
|
||||
{
|
||||
vm_paddr_t highmem;
|
||||
|
||||
romptr = vm_create_devmem(ctx, VM_BOOTROM, "bootrom", BOOTROM_SIZE);
|
||||
if (romptr == MAP_FAILED)
|
||||
err(4, "%s: vm_create_devmem", __func__);
|
||||
gpa_base = (1ULL << 32) - BOOTROM_SIZE;
|
||||
highmem = vm_get_highmem_base(ctx);
|
||||
gpa_base = highmem - BOOTROM_SIZE;
|
||||
gpa_allocbot = gpa_base;
|
||||
gpa_alloctop = (1ULL << 32) - 1;
|
||||
gpa_alloctop = highmem - 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -190,7 +193,7 @@ bootrom_alloc(struct vmctx *ctx, size_t len, int prot, int flags,
|
|||
}
|
||||
|
||||
int
|
||||
bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl)
|
||||
bootrom_loadrom(struct vmctx *ctx)
|
||||
{
|
||||
struct stat sbuf;
|
||||
ssize_t rlen;
|
||||
|
@ -202,9 +205,9 @@ bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl)
|
|||
rv = -1;
|
||||
varfd = -1;
|
||||
|
||||
bootrom = get_config_value_node(nvl, "bootrom");
|
||||
bootrom = get_config_value("bootrom");
|
||||
if (bootrom == NULL) {
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -233,19 +236,19 @@ bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl)
|
|||
|
||||
rom_size = sbuf.st_size;
|
||||
|
||||
varfile = get_config_value_node(nvl, "bootvars");
|
||||
varfile = get_config_value("bootvars");
|
||||
var_size = 0;
|
||||
if (varfile != NULL) {
|
||||
varfd = open(varfile, O_RDWR);
|
||||
if (varfd < 0) {
|
||||
fprintf(stderr, "Error opening bootrom variable file "
|
||||
"\"%s\": %s\n", varfile, strerror(errno));
|
||||
EPRINTLN("Error opening bootrom variable file "
|
||||
"\"%s\": %s", varfile, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (fstat(varfd, &sbuf) < 0) {
|
||||
fprintf(stderr,
|
||||
"Could not fstat bootrom variable file \"%s\": %s\n",
|
||||
EPRINTLN(
|
||||
"Could not fstat bootrom variable file \"%s\": %s",
|
||||
varfile, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
@ -255,7 +258,7 @@ bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl)
|
|||
|
||||
if (var_size > BOOTROM_SIZE ||
|
||||
(var_size != 0 && var_size < PAGE_SIZE)) {
|
||||
fprintf(stderr, "Invalid bootrom variable size %ld\n",
|
||||
EPRINTLN("Invalid bootrom variable size %ld",
|
||||
var_size);
|
||||
goto done;
|
||||
}
|
||||
|
@ -263,8 +266,8 @@ bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl)
|
|||
total_size = rom_size + var_size;
|
||||
|
||||
if (total_size > BOOTROM_SIZE) {
|
||||
fprintf(stderr, "Invalid bootrom and variable aggregate size "
|
||||
"%ld\n", total_size);
|
||||
EPRINTLN("Invalid bootrom and variable aggregate size %ld",
|
||||
total_size);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -317,3 +320,12 @@ done:
|
|||
free(romfile);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Are we relying on a bootrom to initialize the guest's CPU context?
|
||||
*/
|
||||
bool
|
||||
bootrom_boot(void)
|
||||
{
|
||||
return (get_config_value("bootrom") != NULL);
|
||||
}
|
|
@ -45,6 +45,7 @@ enum {
|
|||
};
|
||||
int bootrom_alloc(struct vmctx *ctx, size_t len, int prot, int flags,
|
||||
char **region_out, uint64_t *gpa_out);
|
||||
int bootrom_loadrom(struct vmctx *ctx, const nvlist_t *nvl);
|
||||
bool bootrom_boot(void);
|
||||
int bootrom_loadrom(struct vmctx *ctx);
|
||||
|
||||
#endif
|
|
@ -25,7 +25,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
|
@ -64,6 +63,7 @@
|
|||
|
||||
#include "bhyverun.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "gdb.h"
|
||||
#include "mem.h"
|
||||
#include "mevent.h"
|
||||
|
@ -74,6 +74,13 @@
|
|||
*/
|
||||
#define GDB_SIGNAL_TRAP 5
|
||||
|
||||
#define GDB_BP_SIZE 1
|
||||
#define GDB_BP_INSTR (uint8_t []){0xcc}
|
||||
#define GDB_PC_REGNAME VM_REG_GUEST_RIP
|
||||
|
||||
_Static_assert(sizeof(GDB_BP_INSTR) == GDB_BP_SIZE,
|
||||
"GDB_BP_INSTR has wrong size");
|
||||
|
||||
static void gdb_resume_vcpus(void);
|
||||
static void check_command(int fd);
|
||||
|
||||
|
@ -100,7 +107,7 @@ struct io_buffer {
|
|||
|
||||
struct breakpoint {
|
||||
uint64_t gpa;
|
||||
uint8_t shadow_inst;
|
||||
uint8_t shadow_inst[GDB_BP_SIZE];
|
||||
TAILQ_ENTRY(breakpoint) link;
|
||||
};
|
||||
|
||||
|
@ -139,58 +146,36 @@ static struct vcpu **vcpus;
|
|||
static int cur_vcpu, stopped_vcpu;
|
||||
static bool gdb_active = false;
|
||||
|
||||
static const int gdb_regset[] = {
|
||||
VM_REG_GUEST_RAX,
|
||||
VM_REG_GUEST_RBX,
|
||||
VM_REG_GUEST_RCX,
|
||||
VM_REG_GUEST_RDX,
|
||||
VM_REG_GUEST_RSI,
|
||||
VM_REG_GUEST_RDI,
|
||||
VM_REG_GUEST_RBP,
|
||||
VM_REG_GUEST_RSP,
|
||||
VM_REG_GUEST_R8,
|
||||
VM_REG_GUEST_R9,
|
||||
VM_REG_GUEST_R10,
|
||||
VM_REG_GUEST_R11,
|
||||
VM_REG_GUEST_R12,
|
||||
VM_REG_GUEST_R13,
|
||||
VM_REG_GUEST_R14,
|
||||
VM_REG_GUEST_R15,
|
||||
VM_REG_GUEST_RIP,
|
||||
VM_REG_GUEST_RFLAGS,
|
||||
VM_REG_GUEST_CS,
|
||||
VM_REG_GUEST_SS,
|
||||
VM_REG_GUEST_DS,
|
||||
VM_REG_GUEST_ES,
|
||||
VM_REG_GUEST_FS,
|
||||
VM_REG_GUEST_GS
|
||||
struct gdb_reg {
|
||||
enum vm_reg_name id;
|
||||
int size;
|
||||
};
|
||||
|
||||
static const int gdb_regsize[] = {
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4
|
||||
static const struct gdb_reg gdb_regset[] = {
|
||||
{ .id = VM_REG_GUEST_RAX, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RBX, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RCX, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RDX, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RSI, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RDI, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RBP, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RSP, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R8, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R9, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R10, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R11, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R12, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R13, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R14, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_R15, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RIP, .size = 8 },
|
||||
{ .id = VM_REG_GUEST_RFLAGS, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_CS, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_SS, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_DS, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_ES, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_FS, .size = 4 },
|
||||
{ .id = VM_REG_GUEST_GS, .size = 4 },
|
||||
};
|
||||
|
||||
#ifdef GDB_LOG
|
||||
|
@ -299,6 +284,12 @@ guest_vaddr2paddr(struct vcpu *vcpu, uint64_t vaddr, uint64_t *paddr)
|
|||
return (1);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
guest_pc(struct vm_exit *vme)
|
||||
{
|
||||
return (vme->rip);
|
||||
}
|
||||
|
||||
static void
|
||||
io_buffer_reset(struct io_buffer *io)
|
||||
{
|
||||
|
@ -787,7 +778,7 @@ gdb_cpu_add(struct vcpu *vcpu)
|
|||
CPU_SET(vcpuid, &vcpus_active);
|
||||
if (!TAILQ_EMPTY(&breakpoints)) {
|
||||
vm_set_capability(vcpu, VM_CAP_BPT_EXIT, 1);
|
||||
debug("$vCPU %d enabled breakpoint exits\n", vcpu);
|
||||
debug("$vCPU %d enabled breakpoint exits\n", vcpuid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -909,12 +900,12 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
|
|||
int error, vcpuid;
|
||||
|
||||
if (!gdb_active) {
|
||||
fprintf(stderr, "vm_loop: unexpected VMEXIT_DEBUG\n");
|
||||
EPRINTLN("vm_loop: unexpected VMEXIT_DEBUG");
|
||||
exit(4);
|
||||
}
|
||||
vcpuid = vcpu_id(vcpu);
|
||||
pthread_mutex_lock(&gdb_lock);
|
||||
error = guest_vaddr2paddr(vcpu, vmexit->rip, &gpa);
|
||||
error = guest_vaddr2paddr(vcpu, guest_pc(vmexit), &gpa);
|
||||
assert(error == 1);
|
||||
bp = find_breakpoint(gpa);
|
||||
if (bp != NULL) {
|
||||
|
@ -923,11 +914,11 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
|
|||
assert(vs->stepped == false);
|
||||
assert(vs->hit_swbreak == false);
|
||||
vs->hit_swbreak = true;
|
||||
vm_set_register(vcpu, VM_REG_GUEST_RIP, vmexit->rip);
|
||||
vm_set_register(vcpu, GDB_PC_REGNAME, guest_pc(vmexit));
|
||||
for (;;) {
|
||||
if (stopped_vcpu == -1) {
|
||||
debug("$vCPU %d reporting breakpoint at rip %#lx\n",
|
||||
vcpuid, vmexit->rip);
|
||||
vcpuid, guest_pc(vmexit));
|
||||
stopped_vcpu = vcpuid;
|
||||
gdb_suspend_vcpus();
|
||||
}
|
||||
|
@ -946,7 +937,7 @@ gdb_cpu_breakpoint(struct vcpu *vcpu, struct vm_exit *vmexit)
|
|||
gdb_cpu_resume(vcpu);
|
||||
} else {
|
||||
debug("$vCPU %d injecting breakpoint at rip %#lx\n", vcpuid,
|
||||
vmexit->rip);
|
||||
guest_pc(vmexit));
|
||||
error = vm_set_register(vcpu, VM_REG_GUEST_ENTRY_INST_LENGTH,
|
||||
vmexit->u.bpt.inst_length);
|
||||
assert(error == 0);
|
||||
|
@ -990,15 +981,41 @@ static void
|
|||
gdb_read_regs(void)
|
||||
{
|
||||
uint64_t regvals[nitems(gdb_regset)];
|
||||
int regnums[nitems(gdb_regset)];
|
||||
|
||||
for (size_t i = 0; i < nitems(gdb_regset); i++)
|
||||
regnums[i] = gdb_regset[i].id;
|
||||
if (vm_get_register_set(vcpus[cur_vcpu], nitems(gdb_regset),
|
||||
gdb_regset, regvals) == -1) {
|
||||
regnums, regvals) == -1) {
|
||||
send_error(errno);
|
||||
return;
|
||||
}
|
||||
start_packet();
|
||||
for (size_t i = 0; i < nitems(regvals); i++)
|
||||
append_unsigned_native(regvals[i], gdb_regsize[i]);
|
||||
for (size_t i = 0; i < nitems(gdb_regset); i++)
|
||||
append_unsigned_native(regvals[i], gdb_regset[i].size);
|
||||
finish_packet();
|
||||
}
|
||||
|
||||
static void
|
||||
gdb_read_one_reg(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint64_t regval;
|
||||
uintmax_t reg;
|
||||
|
||||
reg = parse_integer(data, len);
|
||||
if (reg >= nitems(gdb_regset)) {
|
||||
send_error(EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vm_get_register(vcpus[cur_vcpu], gdb_regset[reg].id, ®val) ==
|
||||
-1) {
|
||||
send_error(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
start_packet();
|
||||
append_unsigned_native(regval, gdb_regset[reg].size);
|
||||
finish_packet();
|
||||
}
|
||||
|
||||
|
@ -1011,6 +1028,8 @@ gdb_read_mem(const uint8_t *data, size_t len)
|
|||
bool started;
|
||||
int error;
|
||||
|
||||
assert(len >= 1);
|
||||
|
||||
/* Skip 'm' */
|
||||
data += 1;
|
||||
len -= 1;
|
||||
|
@ -1122,6 +1141,8 @@ gdb_write_mem(const uint8_t *data, size_t len)
|
|||
size_t resid, todo, bytes;
|
||||
int error;
|
||||
|
||||
assert(len >= 1);
|
||||
|
||||
/* Skip 'M' */
|
||||
data += 1;
|
||||
len -= 1;
|
||||
|
@ -1253,8 +1274,8 @@ remove_all_sw_breakpoints(void)
|
|||
|
||||
TAILQ_FOREACH_SAFE(bp, &breakpoints, link, nbp) {
|
||||
debug("remove breakpoint at %#lx\n", bp->gpa);
|
||||
cp = paddr_guest2host(ctx, bp->gpa, 1);
|
||||
*cp = bp->shadow_inst;
|
||||
cp = paddr_guest2host(ctx, bp->gpa, sizeof(bp->shadow_inst));
|
||||
memcpy(cp, bp->shadow_inst, sizeof(bp->shadow_inst));
|
||||
TAILQ_REMOVE(&breakpoints, bp, link);
|
||||
free(bp);
|
||||
}
|
||||
|
@ -1270,7 +1291,7 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
|
|||
uint8_t *cp;
|
||||
int error;
|
||||
|
||||
if (kind != 1) {
|
||||
if (kind != GDB_BP_SIZE) {
|
||||
send_error(EINVAL);
|
||||
return;
|
||||
}
|
||||
|
@ -1285,7 +1306,7 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
|
|||
return;
|
||||
}
|
||||
|
||||
cp = paddr_guest2host(ctx, gpa, 1);
|
||||
cp = paddr_guest2host(ctx, gpa, sizeof(bp->shadow_inst));
|
||||
|
||||
/* Only permit breakpoints in guest RAM. */
|
||||
if (cp == NULL) {
|
||||
|
@ -1309,15 +1330,15 @@ update_sw_breakpoint(uint64_t gva, int kind, bool insert)
|
|||
}
|
||||
bp = malloc(sizeof(*bp));
|
||||
bp->gpa = gpa;
|
||||
bp->shadow_inst = *cp;
|
||||
*cp = 0xcc; /* INT 3 */
|
||||
memcpy(bp->shadow_inst, cp, sizeof(bp->shadow_inst));
|
||||
memcpy(cp, GDB_BP_INSTR, sizeof(bp->shadow_inst));
|
||||
TAILQ_INSERT_TAIL(&breakpoints, bp, link);
|
||||
debug("new breakpoint at %#lx\n", gpa);
|
||||
}
|
||||
} else {
|
||||
if (bp != NULL) {
|
||||
debug("remove breakpoint at %#lx\n", gpa);
|
||||
*cp = bp->shadow_inst;
|
||||
memcpy(cp, bp->shadow_inst, sizeof(bp->shadow_inst));
|
||||
TAILQ_REMOVE(&breakpoints, bp, link);
|
||||
free(bp);
|
||||
if (TAILQ_EMPTY(&breakpoints))
|
||||
|
@ -1526,7 +1547,7 @@ gdb_query(const uint8_t *data, size_t len)
|
|||
|
||||
data += strlen("qThreadExtraInfo");
|
||||
len -= strlen("qThreadExtraInfo");
|
||||
if (*data != ',') {
|
||||
if (len == 0 || *data != ',') {
|
||||
send_error(EINVAL);
|
||||
return;
|
||||
}
|
||||
|
@ -1570,14 +1591,16 @@ handle_command(const uint8_t *data, size_t len)
|
|||
|
||||
/* TODO: Resume any stopped CPUs. */
|
||||
break;
|
||||
case 'g': {
|
||||
case 'g':
|
||||
gdb_read_regs();
|
||||
break;
|
||||
}
|
||||
case 'p':
|
||||
gdb_read_one_reg(data + 1, len - 1);
|
||||
break;
|
||||
case 'H': {
|
||||
int tid;
|
||||
|
||||
if (data[1] != 'g' && data[1] != 'c') {
|
||||
if (len < 2 || (data[1] != 'g' && data[1] != 'c')) {
|
||||
send_error(EINVAL);
|
||||
break;
|
||||
}
|
||||
|
@ -1645,7 +1668,6 @@ handle_command(const uint8_t *data, size_t len)
|
|||
case 'v':
|
||||
/* Handle 'vCont' */
|
||||
/* 'vCtrlC' */
|
||||
case 'p': /* TODO */
|
||||
case 'P': /* TODO */
|
||||
case 'Q': /* TODO */
|
||||
case 't': /* TODO */
|
|
@ -27,7 +27,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
|
@ -32,11 +32,8 @@
|
|||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
|
@ -28,7 +28,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
|
@ -44,7 +44,6 @@
|
|||
* so it can be searched within the range.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
|
@ -36,7 +36,6 @@
|
|||
* using kqueue, and having events be persistent by default.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <assert.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
|
@ -0,0 +1,366 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The illumos dlpi backend
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <libdlpi.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "iov.h"
|
||||
#include "mevent.h"
|
||||
#include "net_backends.h"
|
||||
#include "net_backends_priv.h"
|
||||
|
||||
/*
|
||||
* The size of the bounce buffer used to implement the peek callback.
|
||||
* This value should be big enough to accommodate the largest of all possible
|
||||
* frontend packet lengths. The value here matches the definition of
|
||||
* VTNET_MAX_PKT_LEN in pci_virtio_net.c
|
||||
*/
|
||||
#define DLPI_BBUF_SIZE (65536 + 64)
|
||||
|
||||
typedef struct be_dlpi_priv {
|
||||
dlpi_handle_t bdp_dhp;
|
||||
struct mevent *bdp_mevp;
|
||||
/*
|
||||
* A bounce buffer that allows us to implement the peek_recvlen
|
||||
* callback. Each structure is only used by a single thread so
|
||||
* one is enough.
|
||||
*/
|
||||
uint8_t bdp_bbuf[DLPI_BBUF_SIZE];
|
||||
ssize_t bdp_bbuflen;
|
||||
} be_dlpi_priv_t;
|
||||
|
||||
static void
|
||||
be_dlpi_cleanup(net_backend_t *be)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
|
||||
if (priv->bdp_dhp != NULL)
|
||||
dlpi_close(priv->bdp_dhp);
|
||||
priv->bdp_dhp = NULL;
|
||||
|
||||
if (priv->bdp_mevp != NULL)
|
||||
mevent_delete(priv->bdp_mevp);
|
||||
priv->bdp_mevp = NULL;
|
||||
|
||||
priv->bdp_bbuflen = 0;
|
||||
be->fd = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
be_dlpi_err(int ret, const char *dev, char *msg)
|
||||
{
|
||||
EPRINTLN("%s: %s (%s)", dev, msg, dlpi_strerror(ret));
|
||||
}
|
||||
|
||||
static int
|
||||
be_dlpi_init(net_backend_t *be, const char *devname __unused,
|
||||
nvlist_t *nvl, net_be_rxeof_t cb, void *param)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
const char *vnic;
|
||||
int ret;
|
||||
|
||||
if (cb == NULL) {
|
||||
EPRINTLN("dlpi backend requires non-NULL callback");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
vnic = get_config_value_node(nvl, "vnic");
|
||||
if (vnic == NULL) {
|
||||
EPRINTLN("dlpi backend requires a VNIC");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
priv->bdp_bbuflen = 0;
|
||||
|
||||
ret = dlpi_open(vnic, &priv->bdp_dhp, DLPI_RAW);
|
||||
|
||||
if (ret != DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic, "open failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((ret = dlpi_bind(priv->bdp_dhp, DLPI_ANY_SAP, NULL)) !=
|
||||
DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic, "bind failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (get_config_bool_node_default(nvl, "promiscrxonly", true)) {
|
||||
if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_RX_ONLY)) !=
|
||||
DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic,
|
||||
"enable promiscuous mode(rxonly) failed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (get_config_bool_node_default(nvl, "promiscphys", false)) {
|
||||
if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_PHYS)) !=
|
||||
DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic,
|
||||
"enable promiscuous mode(physical) failed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (get_config_bool_node_default(nvl, "promiscsap", true)) {
|
||||
if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_SAP)) !=
|
||||
DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic,
|
||||
"enable promiscuous mode(SAP) failed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (get_config_bool_node_default(nvl, "promiscmulti", true)) {
|
||||
if ((ret = dlpi_promiscon(priv->bdp_dhp, DL_PROMISC_MULTI)) !=
|
||||
DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, vnic,
|
||||
"enable promiscuous mode(muticast) failed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
be->fd = dlpi_fd(priv->bdp_dhp);
|
||||
|
||||
if (fcntl(be->fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
EPRINTLN("%s: enable O_NONBLOCK failed", vnic);
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->bdp_mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
|
||||
if (priv->bdp_mevp == NULL) {
|
||||
EPRINTLN("Could not register event");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
be_dlpi_cleanup(be);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to send a buffer chain out to the dlpi device
|
||||
*/
|
||||
static ssize_t
|
||||
be_dlpi_send(net_backend_t *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
ssize_t len = 0;
|
||||
int ret;
|
||||
|
||||
if (iovcnt == 1) {
|
||||
len = iov[0].iov_len;
|
||||
ret = dlpi_send(priv->bdp_dhp, NULL, 0, iov[0].iov_base, len,
|
||||
NULL);
|
||||
} else {
|
||||
void *buf = NULL;
|
||||
|
||||
len = iov_to_buf(iov, iovcnt, &buf);
|
||||
|
||||
if (len <= 0 || buf == NULL)
|
||||
return (-1);
|
||||
|
||||
ret = dlpi_send(priv->bdp_dhp, NULL, 0, buf, len, NULL);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (ret != DLPI_SUCCESS)
|
||||
return (-1);
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
be_dlpi_peek_recvlen(net_backend_t *be)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
dlpi_recvinfo_t recv;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We already have a packet in the bounce buffer.
|
||||
* Just return its length.
|
||||
*/
|
||||
if (priv->bdp_bbuflen > 0)
|
||||
return (priv->bdp_bbuflen);
|
||||
|
||||
/*
|
||||
* Read the next packet (if any) into the bounce buffer, so
|
||||
* that we get to know its length and we can return that
|
||||
* to the caller.
|
||||
*/
|
||||
len = sizeof (priv->bdp_bbuf);
|
||||
ret = dlpi_recv(priv->bdp_dhp, NULL, NULL, priv->bdp_bbuf, &len,
|
||||
0, &recv);
|
||||
if (ret == DL_SYSERR) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return (0);
|
||||
return (-1);
|
||||
} else if (ret == DLPI_ETIMEDOUT) {
|
||||
return (0);
|
||||
} else if (ret != DLPI_SUCCESS) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (recv.dri_totmsglen > sizeof (priv->bdp_bbuf)) {
|
||||
EPRINTLN("DLPI bounce buffer was too small! - needed %x bytes",
|
||||
recv.dri_totmsglen);
|
||||
}
|
||||
|
||||
priv->bdp_bbuflen = len;
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
be_dlpi_recv(net_backend_t *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (priv->bdp_bbuflen > 0) {
|
||||
/*
|
||||
* A packet is available in the bounce buffer, so
|
||||
* we read it from there.
|
||||
*/
|
||||
len = buf_to_iov(priv->bdp_bbuf, priv->bdp_bbuflen,
|
||||
iov, iovcnt, 0);
|
||||
|
||||
/* Mark the bounce buffer as empty. */
|
||||
priv->bdp_bbuflen = 0;
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
len = iov[0].iov_len;
|
||||
ret = dlpi_recv(priv->bdp_dhp, NULL, NULL,
|
||||
(uint8_t *)iov[0].iov_base, &len, 0, NULL);
|
||||
if (ret == DL_SYSERR) {
|
||||
if (errno == EWOULDBLOCK)
|
||||
return (0);
|
||||
return (-1);
|
||||
} else if (ret == DLPI_ETIMEDOUT) {
|
||||
return (0);
|
||||
} else if (ret != DLPI_SUCCESS) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
static void
|
||||
be_dlpi_recv_enable(net_backend_t *be)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
|
||||
mevent_enable(priv->bdp_mevp);
|
||||
}
|
||||
|
||||
static void
|
||||
be_dlpi_recv_disable(net_backend_t *be)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
|
||||
mevent_disable(priv->bdp_mevp);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
be_dlpi_get_cap(net_backend_t *be)
|
||||
{
|
||||
return (0); /* no capabilities for now */
|
||||
}
|
||||
|
||||
static int
|
||||
be_dlpi_set_cap(net_backend_t *be, uint64_t features,
|
||||
unsigned vnet_hdr_len)
|
||||
{
|
||||
return ((features || vnet_hdr_len) ? -1 : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
be_dlpi_get_mac(net_backend_t *be, void *buf, size_t *buflen)
|
||||
{
|
||||
be_dlpi_priv_t *priv = NET_BE_PRIV(be);
|
||||
uchar_t physaddr[DLPI_PHYSADDR_MAX];
|
||||
size_t physaddrlen = DLPI_PHYSADDR_MAX;
|
||||
int ret;
|
||||
|
||||
if ((ret = dlpi_get_physaddr(priv->bdp_dhp, DL_CURR_PHYS_ADDR,
|
||||
physaddr, &physaddrlen)) != DLPI_SUCCESS) {
|
||||
be_dlpi_err(ret, dlpi_linkname(priv->bdp_dhp),
|
||||
"read MAC address failed");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (physaddrlen != ETHERADDRL) {
|
||||
EPRINTLN("%s: bad MAC address len %d",
|
||||
dlpi_linkname(priv->bdp_dhp), physaddrlen);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (physaddrlen > *buflen) {
|
||||
EPRINTLN("%s: MAC address too long (%d bytes required)",
|
||||
dlpi_linkname(priv->bdp_dhp), physaddrlen);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
*buflen = physaddrlen;
|
||||
memcpy(buf, physaddr, *buflen);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static struct net_backend dlpi_backend = {
|
||||
.prefix = "dlpi",
|
||||
.priv_size = sizeof(struct be_dlpi_priv),
|
||||
.init = be_dlpi_init,
|
||||
.cleanup = be_dlpi_cleanup,
|
||||
.send = be_dlpi_send,
|
||||
.peek_recvlen = be_dlpi_peek_recvlen,
|
||||
.recv = be_dlpi_recv,
|
||||
.recv_enable = be_dlpi_recv_enable,
|
||||
.recv_disable = be_dlpi_recv_disable,
|
||||
.get_cap = be_dlpi_get_cap,
|
||||
.set_cap = be_dlpi_set_cap,
|
||||
.get_mac = be_dlpi_get_mac,
|
||||
};
|
||||
|
||||
DATA_SET(net_backend_set, dlpi_backend);
|
|
@ -0,0 +1,535 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Vincenzo Maffione <vmaffione@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements multiple network backends (tap, netmap, ...),
|
||||
* to be used by network frontends such as virtio-net and e1000.
|
||||
* The API to access the backend (e.g. send/receive packets, negotiate
|
||||
* features) is exported by net_backends.h.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <sys/capsicum.h>
|
||||
#endif
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <net/if_tap.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
#include <capsicum_helpers.h>
|
||||
#endif
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <pthread_np.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "iov.h"
|
||||
#include "mevent.h"
|
||||
#include "net_backends.h"
|
||||
#include "net_backends_priv.h"
|
||||
#include "pci_emul.h"
|
||||
|
||||
#define NET_BE_SIZE(be) (sizeof(*be) + (be)->priv_size)
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
void
|
||||
tap_cleanup(struct net_backend *be)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
|
||||
if (priv->mevp) {
|
||||
mevent_delete(priv->mevp);
|
||||
}
|
||||
if (be->fd != -1) {
|
||||
close(be->fd);
|
||||
be->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
tap_init(struct net_backend *be, const char *devname,
|
||||
nvlist_t *nvl __unused, net_be_rxeof_t cb, void *param)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
char tbuf[80];
|
||||
int opt = 1, up = IFF_UP;
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
cap_rights_t rights;
|
||||
#endif
|
||||
|
||||
if (cb == NULL) {
|
||||
EPRINTLN("TAP backend requires non-NULL callback");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
strcpy(tbuf, "/dev/");
|
||||
strlcat(tbuf, devname, sizeof(tbuf));
|
||||
|
||||
be->fd = open(tbuf, O_RDWR);
|
||||
if (be->fd == -1) {
|
||||
EPRINTLN("open of tap device %s failed", tbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set non-blocking and register for read
|
||||
* notifications with the event loop
|
||||
*/
|
||||
if (ioctl(be->fd, FIONBIO, &opt) < 0) {
|
||||
EPRINTLN("tap device O_NONBLOCK failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(be->fd, VMIO_SIOCSIFFLAGS, up)) {
|
||||
EPRINTLN("tap device link up failed");
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
cap_rights_init(&rights, CAP_EVENT, CAP_READ, CAP_WRITE);
|
||||
if (caph_rights_limit(be->fd, &rights) == -1)
|
||||
errx(EX_OSERR, "Unable to apply rights for sandbox");
|
||||
#endif
|
||||
|
||||
memset(priv->bbuf, 0, sizeof(priv->bbuf));
|
||||
priv->bbuflen = 0;
|
||||
|
||||
priv->mevp = mevent_add_disabled(be->fd, EVF_READ, cb, param);
|
||||
if (priv->mevp == NULL) {
|
||||
EPRINTLN("Could not register event");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
tap_cleanup(be);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to send a buffer chain out to the tap device
|
||||
*/
|
||||
ssize_t
|
||||
tap_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
return (writev(be->fd, iov, iovcnt));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
tap_peek_recvlen(struct net_backend *be)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
ssize_t ret;
|
||||
|
||||
if (priv->bbuflen > 0) {
|
||||
/*
|
||||
* We already have a packet in the bounce buffer.
|
||||
* Just return its length.
|
||||
*/
|
||||
return priv->bbuflen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next packet (if any) into the bounce buffer, so
|
||||
* that we get to know its length and we can return that
|
||||
* to the caller.
|
||||
*/
|
||||
ret = read(be->fd, priv->bbuf, sizeof(priv->bbuf));
|
||||
if (ret < 0 && errno == EWOULDBLOCK) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
priv->bbuflen = ret;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
tap_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
ssize_t ret;
|
||||
|
||||
if (priv->bbuflen > 0) {
|
||||
/*
|
||||
* A packet is available in the bounce buffer, so
|
||||
* we read it from there.
|
||||
*/
|
||||
ret = buf_to_iov(priv->bbuf, priv->bbuflen,
|
||||
iov, iovcnt, 0);
|
||||
|
||||
/* Mark the bounce buffer as empty. */
|
||||
priv->bbuflen = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret = readv(be->fd, iov, iovcnt);
|
||||
if (ret < 0 && errno == EWOULDBLOCK) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
tap_recv_enable(struct net_backend *be)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
|
||||
mevent_enable(priv->mevp);
|
||||
}
|
||||
|
||||
void
|
||||
tap_recv_disable(struct net_backend *be)
|
||||
{
|
||||
struct tap_priv *priv = NET_BE_PRIV(be);
|
||||
|
||||
mevent_disable(priv->mevp);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
tap_get_cap(struct net_backend *be __unused)
|
||||
{
|
||||
|
||||
return (0); /* no capabilities for now */
|
||||
}
|
||||
|
||||
int
|
||||
tap_set_cap(struct net_backend *be __unused, uint64_t features,
|
||||
unsigned vnet_hdr_len)
|
||||
{
|
||||
|
||||
return ((features || vnet_hdr_len) ? -1 : 0);
|
||||
}
|
||||
|
||||
static struct net_backend tap_backend = {
|
||||
.prefix = "tap",
|
||||
.priv_size = sizeof(struct tap_priv),
|
||||
.init = tap_init,
|
||||
.cleanup = tap_cleanup,
|
||||
.send = tap_send,
|
||||
.peek_recvlen = tap_peek_recvlen,
|
||||
.recv = tap_recv,
|
||||
.recv_enable = tap_recv_enable,
|
||||
.recv_disable = tap_recv_disable,
|
||||
.get_cap = tap_get_cap,
|
||||
.set_cap = tap_set_cap,
|
||||
};
|
||||
|
||||
/* A clone of the tap backend, with a different prefix. */
|
||||
static struct net_backend vmnet_backend = {
|
||||
.prefix = "vmnet",
|
||||
.priv_size = sizeof(struct tap_priv),
|
||||
.init = tap_init,
|
||||
.cleanup = tap_cleanup,
|
||||
.send = tap_send,
|
||||
.peek_recvlen = tap_peek_recvlen,
|
||||
.recv = tap_recv,
|
||||
.recv_enable = tap_recv_enable,
|
||||
.recv_disable = tap_recv_disable,
|
||||
.get_cap = tap_get_cap,
|
||||
.set_cap = tap_set_cap,
|
||||
};
|
||||
|
||||
DATA_SET(net_backend_set, tap_backend);
|
||||
DATA_SET(net_backend_set, vmnet_backend);
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int
|
||||
netbe_legacy_config(nvlist_t *nvl, const char *opts)
|
||||
{
|
||||
char *backend, *cp;
|
||||
|
||||
if (opts == NULL)
|
||||
return (0);
|
||||
|
||||
cp = strchr(opts, ',');
|
||||
if (cp == NULL) {
|
||||
set_config_value_node(nvl, "backend", opts);
|
||||
return (0);
|
||||
}
|
||||
backend = strndup(opts, cp - opts);
|
||||
set_config_value_node(nvl, "backend", backend);
|
||||
free(backend);
|
||||
return (pci_parse_legacy_config(nvl, cp + 1));
|
||||
}
|
||||
#else
|
||||
int
|
||||
netbe_legacy_config(nvlist_t *nvl, const char *opts)
|
||||
{
|
||||
char *config, *name, *tofree, *value;
|
||||
|
||||
if (opts == NULL)
|
||||
return (0);
|
||||
|
||||
/* Default to the 'dlpi' backend - can still be overridden by opts */
|
||||
set_config_value_node(nvl, "backend", "dlpi");
|
||||
set_config_value_node(nvl, "type", "dlpi");
|
||||
|
||||
config = tofree = strdup(opts);
|
||||
if (config == NULL)
|
||||
err(4, "netbe_legacy_config strdup()");
|
||||
while ((name = strsep(&config, ",")) != NULL) {
|
||||
value = strchr(name, '=');
|
||||
if (value != NULL) {
|
||||
*value++ = '\0';
|
||||
set_config_value_node(nvl, name, value);
|
||||
} else {
|
||||
set_config_value_node(nvl, "vnic", name);
|
||||
}
|
||||
}
|
||||
free(tofree);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize a backend and attach to the frontend.
|
||||
* This is called during frontend initialization.
|
||||
* @ret is a pointer to the backend to be initialized
|
||||
* @devname is the backend-name as supplied on the command line,
|
||||
* e.g. -s 2:0,frontend-name,backend-name[,other-args]
|
||||
* @cb is the receive callback supplied by the frontend,
|
||||
* and it is invoked in the event loop when a receive
|
||||
* event is generated in the hypervisor,
|
||||
* @param is a pointer to the frontend, and normally used as
|
||||
* the argument for the callback.
|
||||
*/
|
||||
int
|
||||
netbe_init(struct net_backend **ret, nvlist_t *nvl, net_be_rxeof_t cb,
|
||||
void *param)
|
||||
{
|
||||
struct net_backend **pbe, *nbe, *tbe = NULL;
|
||||
const char *value, *type;
|
||||
char *devname;
|
||||
int err;
|
||||
|
||||
value = get_config_value_node(nvl, "backend");
|
||||
if (value == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
devname = strdup(value);
|
||||
|
||||
/*
|
||||
* Use the type given by configuration if exists; otherwise
|
||||
* use the prefix of the backend as the type.
|
||||
*/
|
||||
type = get_config_value_node(nvl, "type");
|
||||
if (type == NULL)
|
||||
type = devname;
|
||||
|
||||
/*
|
||||
* Find the network backend that matches the user-provided
|
||||
* device name. net_backend_set is built using a linker set.
|
||||
*/
|
||||
SET_FOREACH(pbe, net_backend_set) {
|
||||
if (strncmp(type, (*pbe)->prefix,
|
||||
strlen((*pbe)->prefix)) == 0) {
|
||||
tbe = *pbe;
|
||||
assert(tbe->init != NULL);
|
||||
assert(tbe->cleanup != NULL);
|
||||
assert(tbe->send != NULL);
|
||||
assert(tbe->recv != NULL);
|
||||
assert(tbe->get_cap != NULL);
|
||||
assert(tbe->set_cap != NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = NULL;
|
||||
if (tbe == NULL) {
|
||||
free(devname);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
nbe = calloc(1, NET_BE_SIZE(tbe));
|
||||
*nbe = *tbe; /* copy the template */
|
||||
nbe->fd = -1;
|
||||
nbe->sc = param;
|
||||
nbe->be_vnet_hdr_len = 0;
|
||||
nbe->fe_vnet_hdr_len = 0;
|
||||
|
||||
/* Initialize the backend. */
|
||||
err = nbe->init(nbe, devname, nvl, cb, param);
|
||||
if (err) {
|
||||
free(devname);
|
||||
free(nbe);
|
||||
return (err);
|
||||
}
|
||||
|
||||
*ret = nbe;
|
||||
free(devname);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
netbe_cleanup(struct net_backend *be)
|
||||
{
|
||||
|
||||
if (be != NULL) {
|
||||
be->cleanup(be);
|
||||
free(be);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
netbe_get_cap(struct net_backend *be)
|
||||
{
|
||||
|
||||
assert(be != NULL);
|
||||
return (be->get_cap(be));
|
||||
}
|
||||
|
||||
int
|
||||
netbe_set_cap(struct net_backend *be, uint64_t features,
|
||||
unsigned vnet_hdr_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(be != NULL);
|
||||
|
||||
/* There are only three valid lengths, i.e., 0, 10 and 12. */
|
||||
if (vnet_hdr_len && vnet_hdr_len != VNET_HDR_LEN
|
||||
&& vnet_hdr_len != (VNET_HDR_LEN - sizeof(uint16_t)))
|
||||
return (-1);
|
||||
|
||||
be->fe_vnet_hdr_len = vnet_hdr_len;
|
||||
|
||||
ret = be->set_cap(be, features, vnet_hdr_len);
|
||||
assert(be->be_vnet_hdr_len == 0 ||
|
||||
be->be_vnet_hdr_len == be->fe_vnet_hdr_len);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
netbe_send(struct net_backend *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
|
||||
return (be->send(be, iov, iovcnt));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
netbe_peek_recvlen(struct net_backend *be)
|
||||
{
|
||||
|
||||
return (be->peek_recvlen(be));
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to read a packet from the backend, without blocking.
|
||||
* If no packets are available, return 0. In case of success, return
|
||||
* the length of the packet just read. Return -1 in case of errors.
|
||||
*/
|
||||
ssize_t
|
||||
netbe_recv(struct net_backend *be, const struct iovec *iov, int iovcnt)
|
||||
{
|
||||
|
||||
return (be->recv(be, iov, iovcnt));
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a packet from the backend and discard it.
|
||||
* Returns the size of the discarded packet or zero if no packet was available.
|
||||
* A negative error code is returned in case of read error.
|
||||
*/
|
||||
ssize_t
|
||||
netbe_rx_discard(struct net_backend *be)
|
||||
{
|
||||
/*
|
||||
* MP note: the dummybuf is only used to discard frames,
|
||||
* so there is no need for it to be per-vtnet or locked.
|
||||
* We only make it large enough for TSO-sized segment.
|
||||
*/
|
||||
static uint8_t dummybuf[65536 + 64];
|
||||
struct iovec iov;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
iov.iov_base = dummybuf;
|
||||
#else
|
||||
iov.iov_base = (caddr_t)dummybuf;
|
||||
#endif
|
||||
iov.iov_len = sizeof(dummybuf);
|
||||
|
||||
return netbe_recv(be, &iov, 1);
|
||||
}
|
||||
|
||||
void
|
||||
netbe_rx_disable(struct net_backend *be)
|
||||
{
|
||||
|
||||
return be->recv_disable(be);
|
||||
}
|
||||
|
||||
void
|
||||
netbe_rx_enable(struct net_backend *be)
|
||||
{
|
||||
|
||||
return be->recv_enable(be);
|
||||
}
|
||||
|
||||
size_t
|
||||
netbe_get_vnet_hdr_len(struct net_backend *be)
|
||||
{
|
||||
|
||||
return (be->be_vnet_hdr_len);
|
||||
}
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
int
|
||||
netbe_get_mac(net_backend_t *be, void *buf, size_t *buflen)
|
||||
{
|
||||
if (be->get_mac == NULL)
|
||||
return (ENOTSUP);
|
||||
return (be->get_mac(be, buf, buflen));
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,162 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Vincenzo Maffione <vmaffione@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __NET_BACKENDS_PRIV_H__
|
||||
#define __NET_BACKENDS_PRIV_H__
|
||||
|
||||
#include <sys/linker_set.h>
|
||||
|
||||
/*
|
||||
* Each network backend registers a set of function pointers that are
|
||||
* used to implement the net backends API.
|
||||
* This might need to be exposed if we implement backends in separate files.
|
||||
*/
|
||||
struct net_backend {
|
||||
const char *prefix; /* prefix matching this backend */
|
||||
|
||||
/*
|
||||
* Routines used to initialize and cleanup the resources needed
|
||||
* by a backend. The cleanup function is used internally,
|
||||
* and should not be called by the frontend.
|
||||
*/
|
||||
int (*init)(struct net_backend *be, const char *devname,
|
||||
nvlist_t *nvl, net_be_rxeof_t cb, void *param);
|
||||
void (*cleanup)(struct net_backend *be);
|
||||
|
||||
/*
|
||||
* Called to serve a guest transmit request. The scatter-gather
|
||||
* vector provided by the caller has 'iovcnt' elements and contains
|
||||
* the packet to send.
|
||||
*/
|
||||
ssize_t (*send)(struct net_backend *be, const struct iovec *iov,
|
||||
int iovcnt);
|
||||
|
||||
/*
|
||||
* Get the length of the next packet that can be received from
|
||||
* the backend. If no packets are currently available, this
|
||||
* function returns 0.
|
||||
*/
|
||||
ssize_t (*peek_recvlen)(struct net_backend *be);
|
||||
|
||||
/*
|
||||
* Called to receive a packet from the backend. When the function
|
||||
* returns a positive value 'len', the scatter-gather vector
|
||||
* provided by the caller contains a packet with such length.
|
||||
* The function returns 0 if the backend doesn't have a new packet to
|
||||
* receive.
|
||||
*/
|
||||
ssize_t (*recv)(struct net_backend *be, const struct iovec *iov,
|
||||
int iovcnt);
|
||||
|
||||
/*
|
||||
* Ask the backend to enable or disable receive operation in the
|
||||
* backend. On return from a disable operation, it is guaranteed
|
||||
* that the receive callback won't be called until receive is
|
||||
* enabled again. Note however that it is up to the caller to make
|
||||
* sure that netbe_recv() is not currently being executed by another
|
||||
* thread.
|
||||
*/
|
||||
void (*recv_enable)(struct net_backend *be);
|
||||
void (*recv_disable)(struct net_backend *be);
|
||||
|
||||
/*
|
||||
* Ask the backend for the virtio-net features it is able to
|
||||
* support. Possible features are TSO, UFO and checksum offloading
|
||||
* in both rx and tx direction and for both IPv4 and IPv6.
|
||||
*/
|
||||
uint64_t (*get_cap)(struct net_backend *be);
|
||||
|
||||
/*
|
||||
* Tell the backend to enable/disable the specified virtio-net
|
||||
* features (capabilities).
|
||||
*/
|
||||
int (*set_cap)(struct net_backend *be, uint64_t features,
|
||||
unsigned int vnet_hdr_len);
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
int (*get_mac)(struct net_backend *be, void *, size_t *);
|
||||
#endif
|
||||
|
||||
struct pci_vtnet_softc *sc;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Length of the virtio-net header used by the backend and the
|
||||
* frontend, respectively. A zero value means that the header
|
||||
* is not used.
|
||||
*/
|
||||
unsigned int be_vnet_hdr_len;
|
||||
unsigned int fe_vnet_hdr_len;
|
||||
|
||||
/* Size of backend-specific private data. */
|
||||
size_t priv_size;
|
||||
|
||||
/* Backend-specific private data follows. */
|
||||
};
|
||||
|
||||
#define NET_BE_PRIV(be) ((void *)((be) + 1))
|
||||
|
||||
SET_DECLARE(net_backend_set, struct net_backend);
|
||||
|
||||
#define VNET_HDR_LEN sizeof(struct virtio_net_rxhdr)
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/*
|
||||
* Export the tap backend routines for the benefit of other backends which have
|
||||
* a similar interface to the kernel, i.e., they send and receive data using
|
||||
* standard I/O system calls with a single file descriptor.
|
||||
*/
|
||||
|
||||
struct tap_priv {
|
||||
struct mevent *mevp;
|
||||
/*
|
||||
* A bounce buffer that allows us to implement the peek_recvlen
|
||||
* callback. In the future we may get the same information from
|
||||
* the kevent data.
|
||||
*/
|
||||
char bbuf[1 << 16];
|
||||
ssize_t bbuflen;
|
||||
};
|
||||
|
||||
void tap_cleanup(struct net_backend *be);
|
||||
ssize_t tap_send(struct net_backend *be, const struct iovec *iov, int io
|
||||
vcnt);
|
||||
ssize_t tap_recv(struct net_backend *be, const struct iovec *iov, int io
|
||||
vcnt);
|
||||
ssize_t tap_peek_recvlen(struct net_backend *be);
|
||||
void tap_recv_enable(struct net_backend *be);
|
||||
ssize_t tap_recv(struct net_backend *be, const struct iovec *iov, int io
|
||||
vcnt);
|
||||
void tap_recv_disable(struct net_backend *be);
|
||||
uint64_t tap_get_cap(struct net_backend *be);
|
||||
int tap_set_cap(struct net_backend *be, uint64_t features,
|
||||
unsigned vnet_hdr_len);
|
||||
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#endif /* !__NET_BACKENDS_PRIV_H__ */
|
|
@ -25,7 +25,6 @@
|
|||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <net/ethernet.h>
|
|
@ -27,7 +27,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
||||
|
@ -116,7 +115,6 @@ static FILE *dbg;
|
|||
#else
|
||||
#define DPRINTF(format, arg...)
|
||||
#endif
|
||||
#define WPRINTF(format, arg...) printf(format, ##arg)
|
||||
|
||||
#define AHCI_PORT_IDENT 20 + 1
|
||||
|
||||
|
@ -340,7 +338,7 @@ ahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis)
|
|||
irq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0;
|
||||
break;
|
||||
default:
|
||||
WPRINTF("unsupported fis type %d", ft);
|
||||
EPRINTLN("unsupported fis type %d", ft);
|
||||
return;
|
||||
}
|
||||
if (fis[2] & ATA_S_ERROR) {
|
||||
|
@ -1797,7 +1795,7 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
|
|||
handle_packet_cmd(p, slot, cfis);
|
||||
break;
|
||||
default:
|
||||
WPRINTF("Unsupported cmd:%02x", cfis[2]);
|
||||
EPRINTLN("Unsupported cmd:%02x", cfis[2]);
|
||||
ahci_write_fis_d2h(p, slot, cfis,
|
||||
(ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);
|
||||
break;
|
||||
|
@ -1842,7 +1840,7 @@ ahci_handle_slot(struct ahci_port *p, int slot)
|
|||
#endif
|
||||
|
||||
if (cfis[0] != FIS_TYPE_REGH2D) {
|
||||
WPRINTF("Not a H2D FIS:%02x", cfis[0]);
|
||||
EPRINTLN("Not a H2D FIS:%02x", cfis[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2129,7 +2127,7 @@ pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
|
|||
case AHCI_P_TFD:
|
||||
case AHCI_P_SIG:
|
||||
case AHCI_P_SSTS:
|
||||
WPRINTF("pci_ahci_port: read only registers 0x%"PRIx64"", offset);
|
||||
EPRINTLN("pci_ahci_port: read only registers 0x%"PRIx64"", offset);
|
||||
break;
|
||||
case AHCI_P_SCTL:
|
||||
p->sctl = value;
|
||||
|
@ -2204,7 +2202,7 @@ pci_ahci_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size,
|
|||
else if (offset < (uint64_t)AHCI_OFFSET + sc->ports * AHCI_STEP)
|
||||
pci_ahci_port_write(sc, offset, value);
|
||||
else
|
||||
WPRINTF("pci_ahci: unknown i/o write offset 0x%"PRIx64"", offset);
|
||||
EPRINTLN("pci_ahci: unknown i/o write offset 0x%"PRIx64"", offset);
|
||||
|
||||
pthread_mutex_unlock(&sc->mtx);
|
||||
}
|
||||
|
@ -2302,7 +2300,7 @@ pci_ahci_read(struct pci_devinst *pi, int baridx, uint64_t regoff, int size)
|
|||
value = pci_ahci_port_read(sc, offset);
|
||||
else {
|
||||
value = 0;
|
||||
WPRINTF("pci_ahci: unknown i/o read offset 0x%"PRIx64"",
|
||||
EPRINTLN("pci_ahci: unknown i/o read offset 0x%"PRIx64"",
|
||||
regoff);
|
||||
}
|
||||
value >>= 8 * (regoff & 0x3);
|
|
@ -29,7 +29,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef WITHOUT_CAPSICUM
|
|
@ -39,7 +39,6 @@
|
|||
* Copyright 2018 Joyent, Inc.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker_set.h>
|
||||
|
@ -62,6 +61,7 @@
|
|||
|
||||
#include "acpi.h"
|
||||
#include "bhyverun.h"
|
||||
#include "bootrom.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "inout.h"
|
||||
|
@ -388,7 +388,7 @@ pci_config_read_reg(const struct pcisel *const host_sel, nvlist_t *nvl,
|
|||
if (config == NULL) {
|
||||
return def;
|
||||
} else if (host_sel != NULL && strcmp(config, "host") == 0) {
|
||||
return read_config(host_sel, reg, size);
|
||||
return pci_host_read_config(host_sel, reg, size);
|
||||
} else {
|
||||
return strtol(config, NULL, 16);
|
||||
}
|
||||
|
@ -544,7 +544,7 @@ pci_emul_mem_handler(struct vcpu *vcpu __unused, int dir,
|
|||
struct pci_devinst *pdi = arg1;
|
||||
struct pci_devemu *pe = pdi->pi_d;
|
||||
uint64_t offset;
|
||||
int bidx = (int) arg2;
|
||||
int bidx = (int)arg2;
|
||||
|
||||
assert(bidx <= PCI_BARMAX);
|
||||
assert(pdi->pi_bar[bidx].type == PCIBAR_MEM32 ||
|
||||
|
@ -799,6 +799,24 @@ pci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,
|
|||
TAILQ_INSERT_BEFORE(bar, new_bar, chain);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* Enable PCI BARs only if we don't have a boot ROM, i.e., bhyveload was
|
||||
* used to load the initial guest image. Otherwise, we rely on the boot
|
||||
* ROM to handle this.
|
||||
*/
|
||||
if (!get_config_bool_default("pci.enable_bars", !bootrom_boot()))
|
||||
return (0);
|
||||
#else
|
||||
/*
|
||||
* Enable PCI BARs unless specifically requested not to. Bootroms
|
||||
* generally used in illumos do not perform PCI BAR enumeration
|
||||
* themselves and so need the BARs enabling here.
|
||||
*/
|
||||
if (!get_config_bool_default("pci.enable_bars", true))
|
||||
return (0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pci_passthru devices synchronize their physical and virtual command
|
||||
* register on init. For that reason, the virtual cmd reg should be
|
||||
|
@ -916,8 +934,19 @@ pci_emul_assign_bar(struct pci_devinst *const pdi, const int idx,
|
|||
pci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);
|
||||
}
|
||||
|
||||
if (type != PCIBAR_ROM) {
|
||||
register_bar(pdi, idx);
|
||||
switch (type) {
|
||||
case PCIBAR_IO:
|
||||
if (porten(pdi))
|
||||
register_bar(pdi, idx);
|
||||
break;
|
||||
case PCIBAR_MEM32:
|
||||
case PCIBAR_MEM64:
|
||||
case PCIBAR_MEMHI64:
|
||||
if (memen(pdi))
|
||||
register_bar(pdi, idx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
@ -1091,7 +1120,13 @@ pci_emul_init(struct vmctx *ctx, struct pci_devemu *pde, int bus, int slot,
|
|||
pci_set_cfgdata8(pdi, PCIR_INTLINE, 255);
|
||||
pci_set_cfgdata8(pdi, PCIR_INTPIN, 0);
|
||||
|
||||
pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
|
||||
#ifdef __FreeBSD__
|
||||
if (get_config_bool_default("pci.enable_bars", !bootrom_boot()))
|
||||
pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
|
||||
#else
|
||||
if (get_config_bool_default("pci.enable_bars", true))
|
||||
pci_set_cfgdata8(pdi, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN);
|
||||
#endif
|
||||
|
||||
err = (*pde->pe_init)(pdi, fi->fi_config);
|
||||
if (err == 0)
|
||||
|
@ -1463,7 +1498,8 @@ init_pci(struct vmctx *ctx)
|
|||
pci_emul_iobase = PCI_EMUL_IOBASE;
|
||||
pci_emul_membase32 = PCI_EMUL_MEMBASE32;
|
||||
|
||||
pci_emul_membase64 = 4*GB + vm_get_highmem_size(ctx);
|
||||
pci_emul_membase64 = vm_get_highmem_base(ctx) +
|
||||
vm_get_highmem_size(ctx);
|
||||
pci_emul_membase64 = roundup2(pci_emul_membase64, PCI_EMUL_MEMSIZE64);
|
||||
pci_emul_memlim64 = pci_emul_membase64 + PCI_EMUL_MEMSIZE64;
|
||||
|
||||
|
@ -2205,7 +2241,7 @@ pci_cfgrw(int in, int bus, int slot, int func, int coff, int bytes,
|
|||
|
||||
/*
|
||||
* Just return if there is no device at this slot:func or if the
|
||||
* the guest is doing an un-aligned access.
|
||||
* guest is doing an un-aligned access.
|
||||
*/
|
||||
if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||
|
||||
(coff & (bytes - 1)) != 0) {
|
|
@ -28,7 +28,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
@ -72,10 +71,10 @@ static int fbuf_debug = 1;
|
|||
|
||||
#define DMEMSZ 128
|
||||
|
||||
#define FB_SIZE (16*MB)
|
||||
#define FB_SIZE (32*MB)
|
||||
|
||||
#define COLS_MAX 1920
|
||||
#define ROWS_MAX 1200
|
||||
#define COLS_MAX 3840
|
||||
#define ROWS_MAX 2160
|
||||
|
||||
#define COLS_DEFAULT 1024
|
||||
#define ROWS_DEFAULT 768
|
||||
|
@ -236,7 +235,8 @@ pci_fbuf_baraddr(struct pci_devinst *pi, int baridx, int enabled,
|
|||
if (vm_mmap_memseg(pi->pi_vmctx, address, VM_FRAMEBUFFER, 0,
|
||||
FB_SIZE, prot) != 0)
|
||||
EPRINTLN("pci_fbuf: mmap_memseg failed");
|
||||
sc->fbaddr = address;
|
||||
else
|
||||
sc->fbaddr = address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,26 +321,23 @@ pci_fbuf_parse_config(struct pci_fbuf_softc *sc, nvlist_t *nvl)
|
|||
}
|
||||
|
||||
value = get_config_value_node(nvl, "w");
|
||||
if (value != NULL) {
|
||||
sc->memregs.width = atoi(value);
|
||||
if (sc->memregs.width > COLS_MAX) {
|
||||
EPRINTLN("fbuf: width %d too large", sc->memregs.width);
|
||||
return (-1);
|
||||
}
|
||||
if (sc->memregs.width == 0)
|
||||
sc->memregs.width = 1920;
|
||||
}
|
||||
if (value != NULL)
|
||||
sc->memregs.width = strtol(value, NULL, 10);
|
||||
|
||||
value = get_config_value_node(nvl, "h");
|
||||
if (value != NULL) {
|
||||
sc->memregs.height = atoi(value);
|
||||
if (sc->memregs.height > ROWS_MAX) {
|
||||
EPRINTLN("fbuf: height %d too large",
|
||||
sc->memregs.height);
|
||||
return (-1);
|
||||
}
|
||||
if (sc->memregs.height == 0)
|
||||
sc->memregs.height = 1080;
|
||||
if (value != NULL)
|
||||
sc->memregs.height = strtol(value, NULL, 10);
|
||||
|
||||
if (sc->memregs.width > COLS_MAX ||
|
||||
sc->memregs.height > ROWS_MAX) {
|
||||
EPRINTLN("fbuf: max resolution is %ux%u", COLS_MAX, ROWS_MAX);
|
||||
return (-1);
|
||||
}
|
||||
if (sc->memregs.width < COLS_MIN ||
|
||||
sc->memregs.height < ROWS_MIN) {
|
||||
EPRINTLN("fbuf: minimum resolution is %ux%u",
|
||||
COLS_MIN, ROWS_MIN);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
value = get_config_value_node(nvl, "password");
|
|
@ -27,7 +27,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
|
@ -790,6 +789,11 @@ hda_corb_run(struct hda_softc *sc)
|
|||
int err;
|
||||
|
||||
corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP);
|
||||
if (corb->wp >= corb->size) {
|
||||
DPRINTF("Invalid HDAC_CORBWP %u >= size %u", corb->wp,
|
||||
corb->size);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
while (corb->rp != corb->wp && corb->run) {
|
||||
corb->rp++;
|
|
@ -28,7 +28,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef __FreeBSD__
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
|
@ -28,7 +28,6 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <machine/vmm.h>
|
||||
|
@ -41,6 +40,7 @@
|
|||
#include <vmmapi.h>
|
||||
|
||||
#include "acpi.h"
|
||||
#include "bootrom.h"
|
||||
#include "inout.h"
|
||||
#include "pci_emul.h"
|
||||
#include "pci_irq.h"
|
||||
|
@ -207,7 +207,7 @@ pirq_alloc_pin(struct pci_devinst *pi)
|
|||
|
||||
pirq_cold = 0;
|
||||
|
||||
if (lpc_bootrom()) {
|
||||
if (bootrom_boot()) {
|
||||
/* For external bootrom use fixed mapping. */
|
||||
best_pin = (4 + pi->pi_slot + pi->pi_lintr.pin) % 8;
|
||||
} else {
|
|
@ -53,7 +53,6 @@
|
|||
- intr coalesce
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/errno.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -377,41 +376,40 @@ static void pci_nvme_io_done(struct blockif_req *, int);
|
|||
|
||||
/* Controller Configuration utils */
|
||||
#define NVME_CC_GET_EN(cc) \
|
||||
((cc) >> NVME_CC_REG_EN_SHIFT & NVME_CC_REG_EN_MASK)
|
||||
NVMEV(NVME_CC_REG_EN, cc)
|
||||
#define NVME_CC_GET_CSS(cc) \
|
||||
((cc) >> NVME_CC_REG_CSS_SHIFT & NVME_CC_REG_CSS_MASK)
|
||||
NVMEV(NVME_CC_REG_CSS, cc)
|
||||
#define NVME_CC_GET_SHN(cc) \
|
||||
((cc) >> NVME_CC_REG_SHN_SHIFT & NVME_CC_REG_SHN_MASK)
|
||||
NVMEV(NVME_CC_REG_SHN, cc)
|
||||
#define NVME_CC_GET_IOSQES(cc) \
|
||||
((cc) >> NVME_CC_REG_IOSQES_SHIFT & NVME_CC_REG_IOSQES_MASK)
|
||||
NVMEV(NVME_CC_REG_IOSQES, cc)
|
||||
#define NVME_CC_GET_IOCQES(cc) \
|
||||
((cc) >> NVME_CC_REG_IOCQES_SHIFT & NVME_CC_REG_IOCQES_MASK)
|
||||
NVMEV(NVME_CC_REG_IOCQES, cc)
|
||||
|
||||
#define NVME_CC_WRITE_MASK \
|
||||
((NVME_CC_REG_EN_MASK << NVME_CC_REG_EN_SHIFT) | \
|
||||
(NVME_CC_REG_IOSQES_MASK << NVME_CC_REG_IOSQES_SHIFT) | \
|
||||
(NVME_CC_REG_IOCQES_MASK << NVME_CC_REG_IOCQES_SHIFT))
|
||||
(NVMEM(NVME_CC_REG_EN) | \
|
||||
NVMEM(NVME_CC_REG_IOSQES) | \
|
||||
NVMEM(NVME_CC_REG_IOCQES))
|
||||
|
||||
#define NVME_CC_NEN_WRITE_MASK \
|
||||
((NVME_CC_REG_CSS_MASK << NVME_CC_REG_CSS_SHIFT) | \
|
||||
(NVME_CC_REG_MPS_MASK << NVME_CC_REG_MPS_SHIFT) | \
|
||||
(NVME_CC_REG_AMS_MASK << NVME_CC_REG_AMS_SHIFT))
|
||||
(NVMEM(NVME_CC_REG_CSS) | \
|
||||
NVMEM(NVME_CC_REG_MPS) | \
|
||||
NVMEM(NVME_CC_REG_AMS))
|
||||
|
||||
/* Controller Status utils */
|
||||
#define NVME_CSTS_GET_RDY(sts) \
|
||||
((sts) >> NVME_CSTS_REG_RDY_SHIFT & NVME_CSTS_REG_RDY_MASK)
|
||||
NVMEV(NVME_CSTS_REG_RDY, sts)
|
||||
|
||||
#define NVME_CSTS_RDY (1 << NVME_CSTS_REG_RDY_SHIFT)
|
||||
#define NVME_CSTS_CFS (1 << NVME_CSTS_REG_CFS_SHIFT)
|
||||
#define NVME_CSTS_RDY (NVMEF(NVME_CSTS_REG_RDY, 1))
|
||||
#define NVME_CSTS_CFS (NVMEF(NVME_CSTS_REG_CFS, 1))
|
||||
|
||||
/* Completion Queue status word utils */
|
||||
#define NVME_STATUS_P (1 << NVME_STATUS_P_SHIFT)
|
||||
#define NVME_STATUS_P (NVMEF(NVME_STATUS_P, 1))
|
||||
#define NVME_STATUS_MASK \
|
||||
((NVME_STATUS_SCT_MASK << NVME_STATUS_SCT_SHIFT) |\
|
||||
(NVME_STATUS_SC_MASK << NVME_STATUS_SC_SHIFT))
|
||||
(NVMEM(NVME_STATUS_SCT) | \
|
||||
NVMEM(NVME_STATUS_SC))
|
||||
|
||||
#define NVME_ONCS_DSM (NVME_CTRLR_DATA_ONCS_DSM_MASK << \
|
||||
NVME_CTRLR_DATA_ONCS_DSM_SHIFT)
|
||||
#define NVME_ONCS_DSM NVMEM(NVME_CTRLR_DATA_ONCS_DSM)
|
||||
|
||||
static void nvme_feature_invalid_cb(struct pci_nvme_softc *,
|
||||
struct nvme_feature_obj *,
|
||||
|
@ -451,8 +449,7 @@ pci_nvme_status_tc(uint16_t *status, uint16_t type, uint16_t code)
|
|||
{
|
||||
|
||||
*status &= ~NVME_STATUS_MASK;
|
||||
*status |= (type & NVME_STATUS_SCT_MASK) << NVME_STATUS_SCT_SHIFT |
|
||||
(code & NVME_STATUS_SC_MASK) << NVME_STATUS_SC_SHIFT;
|
||||
*status |= NVMEF(NVME_STATUS_SCT, type) | NVMEF(NVME_STATUS_SC, code);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
|
@ -545,14 +542,14 @@ pci_nvme_init_ctrldata(struct pci_nvme_softc *sc)
|
|||
cd->ver = NVME_REV(1,4);
|
||||
|
||||
cd->cntrltype = NVME_CNTRLTYPE_IO;
|
||||
cd->oacs = 1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT;
|
||||
cd->oaes = NVMEB(NVME_CTRLR_DATA_OAES_NS_ATTR);
|
||||
cd->oacs = NVMEF(NVME_CTRLR_DATA_OACS_FORMAT, 1);
|
||||
cd->oaes = NVMEM(NVME_CTRLR_DATA_OAES_NS_ATTR);
|
||||
cd->acl = 2;
|
||||
cd->aerl = 4;
|
||||
|
||||
/* Advertise 1, Read-only firmware slot */
|
||||
cd->frmw = NVMEB(NVME_CTRLR_DATA_FRMW_SLOT1_RO) |
|
||||
(1 << NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT);
|
||||
cd->frmw = NVMEM(NVME_CTRLR_DATA_FRMW_SLOT1_RO) |
|
||||
NVMEF(NVME_CTRLR_DATA_FRMW_NUM_SLOTS, 1);
|
||||
cd->lpa = 0; /* TODO: support some simple things like SMART */
|
||||
cd->elpe = 0; /* max error log page entries */
|
||||
/*
|
||||
|
@ -566,13 +563,13 @@ pci_nvme_init_ctrldata(struct pci_nvme_softc *sc)
|
|||
cd->cctemp = 0x0157;
|
||||
|
||||
/* SANICAP must not be 0 for Revision 1.4 and later NVMe Controllers */
|
||||
cd->sanicap = (NVME_CTRLR_DATA_SANICAP_NODMMAS_NO <<
|
||||
NVME_CTRLR_DATA_SANICAP_NODMMAS_SHIFT);
|
||||
cd->sanicap = NVMEF(NVME_CTRLR_DATA_SANICAP_NODMMAS,
|
||||
NVME_CTRLR_DATA_SANICAP_NODMMAS_NO);
|
||||
|
||||
cd->sqes = (6 << NVME_CTRLR_DATA_SQES_MAX_SHIFT) |
|
||||
(6 << NVME_CTRLR_DATA_SQES_MIN_SHIFT);
|
||||
cd->cqes = (4 << NVME_CTRLR_DATA_CQES_MAX_SHIFT) |
|
||||
(4 << NVME_CTRLR_DATA_CQES_MIN_SHIFT);
|
||||
cd->sqes = NVMEF(NVME_CTRLR_DATA_SQES_MAX, 6) |
|
||||
NVMEF(NVME_CTRLR_DATA_SQES_MIN, 6);
|
||||
cd->cqes = NVMEF(NVME_CTRLR_DATA_CQES_MAX, 4) |
|
||||
NVMEF(NVME_CTRLR_DATA_CQES_MIN, 4);
|
||||
cd->nn = 1; /* number of namespaces */
|
||||
|
||||
cd->oncs = 0;
|
||||
|
@ -588,10 +585,9 @@ pci_nvme_init_ctrldata(struct pci_nvme_softc *sc)
|
|||
break;
|
||||
}
|
||||
|
||||
cd->fna = NVME_CTRLR_DATA_FNA_FORMAT_ALL_MASK <<
|
||||
NVME_CTRLR_DATA_FNA_FORMAT_ALL_SHIFT;
|
||||
cd->fna = NVMEM(NVME_CTRLR_DATA_FNA_FORMAT_ALL);
|
||||
|
||||
cd->vwc = NVME_CTRLR_DATA_VWC_ALL_NO << NVME_CTRLR_DATA_VWC_ALL_SHIFT;
|
||||
cd->vwc = NVMEF(NVME_CTRLR_DATA_VWC_ALL, NVME_CTRLR_DATA_VWC_ALL_NO);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
ret = snprintf(cd->subnqn, sizeof(cd->subnqn),
|
||||
|
@ -651,7 +647,7 @@ pci_nvme_init_nsdata(struct pci_nvme_softc *sc,
|
|||
be64enc(nd->eui64, nvstore->eui64);
|
||||
|
||||
/* LBA data-sz = 2^lbads */
|
||||
nd->lbaf[0] = nvstore->sectsz_bits << NVME_NS_DATA_LBAF_LBADS_SHIFT;
|
||||
nd->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS, nvstore->sectsz_bits);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -674,7 +670,7 @@ pci_nvme_init_logpages(struct pci_nvme_softc *sc)
|
|||
sc->health_log.available_spare_threshold = 10;
|
||||
|
||||
/* Set Active Firmware Info to slot 1 */
|
||||
sc->fw_log.afi = (1 << NVME_FIRMWARE_PAGE_AFI_SLOT_SHIFT);
|
||||
sc->fw_log.afi = NVMEF(NVME_FIRMWARE_PAGE_AFI_SLOT, 1);
|
||||
memcpy(&sc->fw_log.revision[0], sc->ctrldata.fr,
|
||||
sizeof(sc->fw_log.revision[0]));
|
||||
|
||||
|
@ -1026,10 +1022,10 @@ pci_nvme_reset_locked(struct pci_nvme_softc *sc)
|
|||
DPRINTF("%s", __func__);
|
||||
|
||||
sc->regs.cap_lo = (ZERO_BASED(sc->max_qentries) & NVME_CAP_LO_REG_MQES_MASK) |
|
||||
(1 << NVME_CAP_LO_REG_CQR_SHIFT) |
|
||||
(60 << NVME_CAP_LO_REG_TO_SHIFT);
|
||||
NVMEF(NVME_CAP_LO_REG_CQR, 1) |
|
||||
NVMEF(NVME_CAP_LO_REG_TO, 60);
|
||||
|
||||
sc->regs.cap_hi = 1 << NVME_CAP_HI_REG_CSS_NVM_SHIFT;
|
||||
sc->regs.cap_hi = NVMEF(NVME_CAP_HI_REG_CSS_NVM, 1);
|
||||
|
||||
sc->regs.vs = NVME_REV(1,4); /* NVMe v1.4 */
|
||||
|
||||
|
@ -1086,7 +1082,7 @@ pci_nvme_init_controller(struct pci_nvme_softc *sc)
|
|||
* cleared to 0h produces undefined results" for both ACQS and
|
||||
* ASQS. If zero, set CFS and do not become ready.
|
||||
*/
|
||||
asqs = ONE_BASED(sc->regs.aqa & NVME_AQA_REG_ASQS_MASK);
|
||||
asqs = ONE_BASED(NVMEV(NVME_AQA_REG_ASQS, sc->regs.aqa));
|
||||
if (asqs < 2) {
|
||||
EPRINTLN("%s: illegal ASQS value %#x (aqa=%#x)", __func__,
|
||||
asqs - 1, sc->regs.aqa);
|
||||
|
@ -1106,8 +1102,7 @@ pci_nvme_init_controller(struct pci_nvme_softc *sc)
|
|||
DPRINTF("%s mapping Admin-SQ guest 0x%lx, host: %p",
|
||||
__func__, sc->regs.asq, sc->submit_queues[0].qbase);
|
||||
|
||||
acqs = ONE_BASED((sc->regs.aqa >> NVME_AQA_REG_ACQS_SHIFT) &
|
||||
NVME_AQA_REG_ACQS_MASK);
|
||||
acqs = ONE_BASED(NVMEV(NVME_AQA_REG_ACQS, sc->regs.aqa));
|
||||
if (acqs < 2) {
|
||||
EPRINTLN("%s: illegal ACQS value %#x (aqa=%#x)", __func__,
|
||||
acqs - 1, sc->regs.aqa);
|
||||
|
@ -2104,8 +2099,8 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, uint64_t value)
|
|||
break;
|
||||
case NVME_OPC_FORMAT_NVM:
|
||||
DPRINTF("%s command FORMAT_NVM", __func__);
|
||||
if ((sc->ctrldata.oacs &
|
||||
(1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT)) == 0) {
|
||||
if (NVMEV(NVME_CTRLR_DATA_OACS_FORMAT,
|
||||
sc->ctrldata.oacs) == 0) {
|
||||
pci_nvme_status_genc(&compl.status, NVME_SC_INVALID_OPCODE);
|
||||
break;
|
||||
}
|
||||
|
@ -2760,8 +2755,7 @@ pci_nvme_handle_io_cmd(struct pci_nvme_softc* sc, uint16_t idx)
|
|||
if ((nsid == 0) || (nsid > sc->ctrldata.nn)) {
|
||||
pci_nvme_status_genc(&status,
|
||||
NVME_SC_INVALID_NAMESPACE_OR_FORMAT);
|
||||
status |=
|
||||
NVME_STATUS_DNR_MASK << NVME_STATUS_DNR_SHIFT;
|
||||
status |= NVMEM(NVME_STATUS_DNR);
|
||||
goto complete;
|
||||
}
|
||||
|
||||
|
@ -2985,10 +2979,9 @@ pci_nvme_write_bar_0(struct pci_nvme_softc *sc, uint64_t offset, int size,
|
|||
|
||||
if (NVME_CC_GET_SHN(ccreg)) {
|
||||
/* perform shutdown - flush out data to backend */
|
||||
sc->regs.csts &= ~(NVME_CSTS_REG_SHST_MASK <<
|
||||
NVME_CSTS_REG_SHST_SHIFT);
|
||||
sc->regs.csts |= NVME_SHST_COMPLETE <<
|
||||
NVME_CSTS_REG_SHST_SHIFT;
|
||||
sc->regs.csts &= ~NVMEM(NVME_CSTS_REG_SHST);
|
||||
sc->regs.csts |= NVMEF(NVME_CSTS_REG_SHST,
|
||||
NVME_SHST_COMPLETE);
|
||||
}
|
||||
if (NVME_CC_GET_EN(ccreg) != NVME_CC_GET_EN(sc->regs.cc)) {
|
||||
if (NVME_CC_GET_EN(ccreg) == 0)
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -617,13 +616,15 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc)
|
|||
{
|
||||
int error;
|
||||
struct pci_devinst *pi = sc->psc_pi;
|
||||
uint16_t cmd;
|
||||
uint8_t intline, intpin;
|
||||
|
||||
/*
|
||||
* Copy physical PCI header to virtual config space. INTLINE and INTPIN
|
||||
* shouldn't be aligned with their physical value and they are already
|
||||
* set by pci_emul_init().
|
||||
* Copy physical PCI header to virtual config space. COMMAND,
|
||||
* INTLINE and INTPIN shouldn't be aligned with their physical value
|
||||
* and they are already set by pci_emul_init().
|
||||
*/
|
||||
cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
|
||||
intline = pci_get_cfgdata8(pi, PCIR_INTLINE);
|
||||
intpin = pci_get_cfgdata8(pi, PCIR_INTPIN);
|
||||
for (int i = 0; i <= PCIR_MAXLAT; i += 4) {
|
||||
|
@ -634,6 +635,7 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc)
|
|||
#endif
|
||||
}
|
||||
|
||||
pci_set_cfgdata16(pi, PCIR_COMMAND, cmd);
|
||||
pci_set_cfgdata8(pi, PCIR_INTLINE, intline);
|
||||
pci_set_cfgdata8(pi, PCIR_INTPIN, intpin);
|
||||
|
||||
|
@ -647,13 +649,6 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
passthru_write_config(sc, PCIR_COMMAND, 2,
|
||||
pci_get_cfgdata16(pi, PCIR_COMMAND));
|
||||
|
||||
/*
|
||||
* We need to do this after PCIR_COMMAND got possibly updated, e.g.,
|
||||
* a BAR was enabled.
|
||||
*/
|
||||
if (pci_msix_table_bar(pi) >= 0) {
|
||||
error = init_msix_table(ctx, sc);
|
||||
if (error != 0) {
|
||||
|
@ -668,7 +663,7 @@ cfginit(struct vmctx *ctx, struct passthru_softc *sc)
|
|||
passthru_cfgread_emulate, passthru_cfgwrite_emulate)) != 0)
|
||||
goto done;
|
||||
|
||||
/* Allow access to the physical command and status register. */
|
||||
/* Allow access to the physical status register. */
|
||||
if ((error = set_pcir_handler(sc, PCIR_COMMAND, 0x04, NULL, NULL)) != 0)
|
||||
goto done;
|
||||
|
||||
|
@ -969,27 +964,25 @@ passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi,
|
|||
return (0);
|
||||
}
|
||||
|
||||
#ifdef LEGACY_SUPPORT
|
||||
/*
|
||||
* If this device does not support MSI natively then we cannot let
|
||||
* the guest disable legacy interrupts from the device. It is the
|
||||
* legacy interrupt that is triggering the virtual MSI to the guest.
|
||||
* The command register is emulated, but the status register
|
||||
* is passed through.
|
||||
*/
|
||||
if (sc->psc_msi.emulated && pci_msi_enabled(pi)) {
|
||||
if (coff == PCIR_COMMAND && bytes == 2)
|
||||
val &= ~PCIM_CMD_INTxDIS;
|
||||
if (coff == PCIR_COMMAND) {
|
||||
if (bytes <= 2)
|
||||
return (-1);
|
||||
|
||||
/* Update the physical status register. */
|
||||
passthru_write_config(sc, PCIR_STATUS, 2, val >> 16);
|
||||
|
||||
/* Update the virtual command register. */
|
||||
cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND);
|
||||
pci_set_cfgdata16(pi, PCIR_COMMAND, val & 0xffff);
|
||||
pci_emul_cmd_changed(pi, cmd_old);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
passthru_write_config(sc, coff, bytes, val);
|
||||
if (coff == PCIR_COMMAND) {
|
||||
cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND);
|
||||
if (bytes == 1)
|
||||
pci_set_cfgdata8(pi, PCIR_COMMAND, val);
|
||||
else if (bytes == 2)
|
||||
pci_set_cfgdata16(pi, PCIR_COMMAND, val);
|
||||
pci_emul_cmd_changed(pi, cmd_old);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -1188,15 +1181,15 @@ PCI_EMUL_SET(passthru);
|
|||
* have access to the devinfo tree.
|
||||
*/
|
||||
uint32_t
|
||||
read_config(const struct pcisel *sel __unused, long reg __unused,
|
||||
pci_host_read_config(const struct pcisel *sel __unused, long reg __unused,
|
||||
int width __unused)
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void
|
||||
write_config(const struct pcisel *sel __unused, long reg __unused,
|
||||
pci_host_write_config(const struct pcisel *sel __unused, long reg __unused,
|
||||
int width __unused, uint32_t data __unused)
|
||||
{
|
||||
errx(4, "write_config() unimplemented on illumos");
|
||||
errx(4, "pci_host_write_config() unimplemented on illumos");
|
||||
}
|
|
@ -19,8 +19,10 @@ typedef int (*cfgread_handler)(struct passthru_softc *sc,
|
|||
typedef int (*cfgwrite_handler)(struct passthru_softc *sc,
|
||||
struct pci_devinst *pi, int coff, int bytes, uint32_t val);
|
||||
|
||||
uint32_t read_config(const struct pcisel *sel, long reg, int width);
|
||||
void write_config(const struct pcisel *sel, long reg, int width, uint32_t data);
|
||||
uint32_t pci_host_read_config(const struct pcisel *sel, long reg, int width);
|
||||
void pci_host_write_config(const struct pcisel *sel, long reg, int width,
|
||||
uint32_t data);
|
||||
|
||||
int passthru_cfgread_emulate(struct passthru_softc *sc, struct pci_devinst *pi,
|
||||
int coff, int bytes, uint32_t *rv);
|
||||
int passthru_cfgwrite_emulate(struct passthru_softc *sc, struct pci_devinst *pi,
|
|
@ -26,7 +26,6 @@
|
|||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -69,7 +68,7 @@ pci_uart_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size,
|
|||
assert(baridx == 0);
|
||||
assert(size == 1);
|
||||
|
||||
uart_write(pi->pi_arg, offset, value);
|
||||
uart_ns16550_write(pi->pi_arg, offset, value);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
|
@ -80,7 +79,7 @@ pci_uart_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size)
|
|||
assert(baridx == 0);
|
||||
assert(size == 1);
|
||||
|
||||
val = uart_read(pi->pi_arg, offset);
|
||||
val = uart_ns16550_read(pi->pi_arg, offset);
|
||||
return (val);
|
||||
}
|
||||
|
||||
|
@ -96,10 +95,10 @@ pci_uart_legacy_config(nvlist_t *nvl, const char *opts)
|
|||
static int
|
||||
pci_uart_init(struct pci_devinst *pi, nvlist_t *nvl)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
struct uart_ns16550_softc *sc;
|
||||
const char *device;
|
||||
|
||||
pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_IO_BAR_SIZE);
|
||||
pci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_NS16550_IO_BAR_SIZE);
|
||||
pci_lintr_request(pi);
|
||||
|
||||
/* initialize config space */
|
||||
|
@ -107,11 +106,12 @@ pci_uart_init(struct pci_devinst *pi, nvlist_t *nvl)
|
|||
pci_set_cfgdata16(pi, PCIR_VENDOR, COM_VENDOR);
|
||||
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);
|
||||
|
||||
sc = uart_init(pci_uart_intr_assert, pci_uart_intr_deassert, pi);
|
||||
sc = uart_ns16550_init(pci_uart_intr_assert, pci_uart_intr_deassert,
|
||||
pi);
|
||||
pi->pi_arg = sc;
|
||||
|
||||
device = get_config_value_node(nvl, "path");
|
||||
if (uart_set_backend(sc, device) != 0) {
|
||||
if (device != NULL && uart_ns16550_tty_open(sc, device) != 0) {
|
||||
EPRINTLN("Unable to initialize backend '%s' for "
|
||||
"pci uart at %d:%d", device, pi->pi_slot, pi->pi_func);
|
||||
return (-1);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue