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:
Andy Fiddaman 2024-05-24 14:18:52 +00:00
parent 535ba94690
commit 5c4a5fe167
163 changed files with 5516 additions and 5357 deletions

View File

@ -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

View File

@ -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/*

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -27,7 +27,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -38,7 +38,6 @@
* Copyright 2020 Oxide Computer Company
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/linker_set.h>

View File

@ -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;

View File

@ -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);
}

View File

@ -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>

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/errno.h>

View File

@ -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);
}
}

View File

@ -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_ */

View File

@ -31,7 +31,6 @@
* Copyright 2020 Oxide Computer Company
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/vmm.h>

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -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);

View File

@ -27,7 +27,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -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);

View File

@ -38,7 +38,6 @@
* Copyright 2020 Oxide Computer Company
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/_iovec.h>

View File

@ -30,7 +30,6 @@
* Copyright 2018 Joyent, Inc.
*/
#include <sys/cdefs.h>
#include <sys/param.h>

View File

@ -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,
};

View File

@ -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

View File

@ -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);
}

View File

@ -27,7 +27,6 @@
*
*/
#include <sys/cdefs.h>
#ifndef WITHOUT_CAPSICUM
#include <sys/capsicum.h>

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -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);
}

View File

@ -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

View File

@ -31,7 +31,6 @@
* Copyright 2020 Joyent, Inc.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#ifndef WITHOUT_CAPSICUM

View File

@ -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);
}

View File

@ -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

View File

@ -25,7 +25,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <assert.h>
#include <err.h>

View File

@ -26,7 +26,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>

View File

@ -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, &regval) ==
-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 */

View File

@ -27,7 +27,6 @@
*
*/
#include <sys/cdefs.h>
#include <pthread.h>
#include <pthread_np.h>

View File

@ -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>

View File

@ -28,7 +28,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/types.h>

View File

@ -44,7 +44,6 @@
* so it can be searched within the range.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/errno.h>

View File

@ -36,7 +36,6 @@
* using kqueue, and having events be persistent by default.
*/
#include <sys/cdefs.h>
#include <assert.h>
#ifndef WITHOUT_CAPSICUM

View File

@ -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);

View File

@ -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

View File

@ -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__ */

View File

@ -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>

View File

@ -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);

View File

@ -29,7 +29,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#ifndef WITHOUT_CAPSICUM

View File

@ -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) {

View File

@ -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");

View File

@ -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++;

View File

@ -28,7 +28,6 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef __FreeBSD__
#include <errno.h>
#include <stdlib.h>

View File

@ -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 {

View File

@ -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)

View File

@ -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");
}

View File

@ -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,

View File

@ -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